您的位置:首页 > 其它

2013 多校第六场 hdu 4664 Triangulation(SG问题)

2013-08-10 17:01 357 查看
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4664

题目大意:N个平面,每个平面有ni个点,组成凸多边形,两个人玩游戏,划线,他们可以划任意一个平面的两个点,有以下要求:两个人划得线不能交叉,不要划已经划过的线,如果一个平面被划了一个空心的三角形,那么这个平面就不能继续划线了。Carol先来,两个人轮着画,谁没线划了就输了,问你最后谁赢。

思路:SG问题。先考虑一个平面,因为画成三角形,就没得画了,所以谁都不能去画一条公共顶点的线,要不然就是自寻死路,因为对方再画一条,你就输了,所以,所有划得线都是不能有公共顶点的,也就是每画一条线,就把这个平面又分成了两个平面,也就是SG定理中的异或,即sg[ n ] = mex(sg[ i ] ^sg[n - i - 2])。由于ni很大,不能直接来,还需要打表,找循环节。这里打印前100个可以发现,有一个循环节,长度是34,。最后再把所有的平面都异或起来就好了。

这里还有一点需要注意,循环节不要从39开始,100左右差不多,因为中间有一个sg[ 52 ]!=sg[ 86 ]。太坑了,比赛的时候,我们就是从39开始计算的,WA了很多遍,还好最后被队友发现了。。= =

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int sg[] = {0,0,1,1,2,0,3,1,1,0,3,3,2,2,4,0,5,2,2,3,3,0,1,1,3,0,2,1,1,0,4,5,2,7,4,0,1,1,2,
0,3,1,1,0,3,3,2,2,4,4,5,5,2,3,3,0,1,1,3,0,2,1,1,0,4,5,3,7,4,8,1,1,2,
0,3,1,1,0,3,3,2,2,4,4,5,5,9,3,3,0,1,1,3,0,2,1,1,0,4,5,3,7,4,8,1,1,2,
0,3,1,1,0,3,3,2,2,4,4,5,5,9,3,3,0,1,1,3,0,2,1,1,0,4,5,3,7,4,8,1,1,2,
0,3,1,1,0,3,3,2,2,4,4,5,5,9,3,3,0,1,1,3,0,2,1,1,0,4,5,3,7,4,8,1,1,2,
0,3,1,1,0,3,3,2,2,4,4,5,5,9,3,3,0,1,1,3,0,2,1,1,0,4};

int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
int ans = 0;
for(int i = 1;i<=n;i++)
{
int a;
scanf("%d",&a);
if(a<100) ans = ans^sg[a];
else ans = ans^sg[(a-100)%34 + 100];
}
if(ans == 0)
puts("Dave");
else puts("Carol");
}
return 0;
}


打表代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAXN = 1111;

int sg[MAXN];

int get_sg(int n)
{
if(sg
!=-1) return sg
;
int hash[MAXN] = {0};
for(int i = 0;i<n-1;i++)
{
int j = n - i - 2;
sg[i] = get_sg(i);
sg[j] = get_sg(j);
hash[sg[i]^sg[j]] = 1;
}
for(int i = 0;;i++)
if(hash[i]==0)
return i;
}

int main()
{
//freopen("D://out.txt","w",stdout);
memset(sg,-1,sizeof(sg));
sg[1] = 0;
sg[2] = 1;
for(int i = 1;i<=200;i++)
{
sg[i] = get_sg(i);
printf("%d,",sg[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: