标签:
题意:
一个n行20列的棋盘。 每一行有若干个棋子。
两人轮流操作, 每人每次可以将一个棋子向右移动一个位置, 如果它右边有一个棋子, 就跳过这个棋子, 如果有若干个棋子, 就将这若干个都跳过。
但是棋子不能移出边界。
如果没有办法移动了, 就算输。 问你先走的能否赢。
分析:
使用状压的SG.
把每一列的答案异或起来.
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int SIZE = 1<<21; 6 int SG[SIZE]; 7 int t, n, m; 8 int GetSG(int x) 9 { 10 if(SG[x] != -1) return SG[x]; 11 int vis[50]={0},nxt=-1; 12 for(int i = 0; i < 20; i++) 13 { 14 if((x&(1 << i)) == 0) nxt=i;//离棋子最近的空格 15 else if(nxt != -1) { 16 vis[GetSG(x ^ (1<<i) | (1<<nxt))] = 1;//该棋子走向空格 17 } 18 } 19 for(int i = 0; ; i++) 20 { 21 if(!vis[i]) return SG[x] = i; 22 } 23 } 24 void Init() 25 { 26 memset(SG,-1,sizeof(SG)); 27 for(int i = 0; i <= 20; i++) SG[(1<<i) - 1] = 0; 28 for(int i = 1; i < (1<<20); i++) if(SG[i] == -1) GetSG(i); 29 } 30 int main() 31 { 32 Init(); 33 scanf("%d",&t); 34 while(t--) 35 { 36 int ans = 0; 37 scanf("%d",&n); 38 while(n--) 39 { 40 scanf("%d",&m); 41 int x,p = 0; 42 while(m--) 43 { 44 scanf("%d",&x); 45 p |= 1 << (20 - x);//左右互换,走到20变为走到 1 46 } 47 ans ^= SG[p];//所有答案异或 48 } 49 if(ans) puts("YES"); 50 else puts("NO"); 51 } 52 return 0; 53 }
标签:
原文地址:http://www.cnblogs.com/nicetomeetu/p/5701888.html