hdu 4664 划线(SG)

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

一个平面上连接点时,不能连接已经有边的顶点,因为对方只需要再连接一次就可以组成一个三角形了

SG[i] i表示剩余没连线的点

0,1个点都是先手必败 SG=0 2,3个点先手必胜 SG[2] = 1 SG[3] = 1

假如 一个平面有4个点 则有以下后继状态
状态1 剩余的两点在已划线的同一侧 SG[0]^SG[2] = 1
状态2 剩余的两点分别在已划线的两侧 SG[1]^SG[1] = 0
所以SG[4] = 2 ;

打表后发现 前面是无序的 后面的SG值会出现长度为34的循环节


Sample Input
2 //T
1 //n
2 //每个平面有多少点
2
2 2

Sample Output
Carol
Dave

 

 1 # include <iostream>
 2 # include <cstdio>
 3 # include <cstring>
 4 # include <algorithm>
 5 # include <string>
 6 # include <cmath>
 7 # include <queue>
 8 # include <list>
 9 # define LL long long
10 using namespace std ;
11 
12 const int MAXN = 100010;
13 int sg[MAXN];
14 bool vis[MAXN];
15 int mex(int x)
16 {
17 
18     if(sg[x]!=-1)return sg[x];
19     if(x == 0)return sg[x] = 0;
20     if(x == 1)return sg[x] = 0;
21     if(x == 2)return sg[x] = 1;
22     if(x == 3)return sg[x] = 1;
23     memset(vis,false,sizeof(vis));
24     for(int i = 0;i < x-1;i++)
25         vis[mex(i)^mex(x-i-2)] = true;
26     for(int i = 0;;i++)
27         if(!vis[i])
28             return sg[x] = i;
29 }
30 
31 int SG(int x)
32 {
33     if(x <= 200)return sg[x];
34     else
35     {
36         x %= 34;
37         x += 2*34;
38         return sg[x];
39     }
40 }
41 
42 int main()
43 {
44     //freopen("in.txt","r",stdin);
45     //freopen("out.txt","w",stdout);
46     memset(sg,-1,sizeof(sg));
47     for(int i = 0;i <= 1000;i++)
48     {
49         sg[i] = mex(i);
50     }
51     int T;
52     int n;
53     int a;
54     scanf("%d",&T);
55     while(T--)
56     {
57         scanf("%d",&n);
58         int sum = 0;
59         for(int i = 0;i < n;i++)
60         {
61             scanf("%d",&a);
62             sum ^= SG(a);
63         }
64         if(sum)printf("Carol\n");
65         else printf("Dave\n");
66     }
67     return 0;
68 }
View Code

 

posted @ 2015-09-28 23:23  __Meng  阅读(188)  评论(0编辑  收藏  举报