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 }