题目:传送门。
题意:有n行,每行最多20个棋子,对于一个棋子来说,如果他右面没有棋子,可以移动到他右面;如果有棋子,就跳过这些棋子移动到后面的空格,不能移动的人输。
题解:状态压缩博弈,对于一行2^20-1种情况来说处理出每一种情况的后继状态,求出sg值,进行异或即可。
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> using namespace std; int sg[(1<<20)+1000]; bool vis[105];//开10^4会超时 void get() { memset(sg,0,sizeof(sg)); for(int i=1;i<(1<<20);i++) { memset(vis,0,sizeof(vis)); int last=-1; for(int j=0;j<20;j++) { if(!((i>>j)&1)) //标记可以走到的0的位置 last=j; if(((i>>j)&1)&&(last!=-1)) vis[sg[i^(1<<j)^(1<<last)]]=1; //就是从1走到0的意思 表示后继状态 } for(int x=0;;x++) { if(!vis[x]) { sg[i]=x; break; } } } } int main() { get(); //for(int i=0;i<200;i++) //printf("sg[%d]=%d ",i,sg[i]); int t; scanf("%d",&t); while(t--) { int n,m,ans=0,sum=0,x; scanf("%d",&n); //要用scanf 用cin会超时 for(int i=0;i<n;i++) { sum=0; scanf("%d",&m); for(int j=0;j<m;j++) { scanf("%d",&x); // 这里写成sum+=或者sum^=都可以;推荐写成sum^=; // 写成sum=sum+1<<(20-x)会RE; // 写成sum=sum^1<<(20-x)不会RE; // 因为移位运算符优先级比加法低所以会RE // 而移位运算符优先级比异或高所以不会RE // 所以 优先级 + 大于 >> 大于 ^ // 当然可以加括号来用 sum^=1<<(20-x); } ans^=sg[sum]; } if(ans) puts("YES"); else puts("NO"); } return 0; }