题目大意:
有一个n*20的棋盘,上面有若干棋子
对于一个棋子,能将它向右移动一格,如果右边有棋子,则向右跳到第一个空格,如果右边没有空格,则不能移动这个棋子,如果所有棋子都不能移动,那么将输掉这场比赛
思路:
我们考虑sg函数,显然最后一个状态下,右边全是一是必赢的,然后我们暴力搜出所有sg函数的,这样就可以o(1)判断了。
程序:
#include<cstdio>
#include<cstdlib>
#include<cstring>
const int N=1048578;
int sg[N],rec[N];
int t,n,m,sum,p,x;
void get_sg(int x){
if (~sg[x]) return;
for (int i=0;i<=19;i++) if (x&(1<<i)){
for (int j=i+1;j<=19;j++) if (!(x&(1<<j))){
int y=x; y=y^(1<<i); y=y^(1<<j);
get_sg(y);
break;
}
}
for (int i=0;i<=19;i++) if (x&(1<<i)){
for (int j=i+1;j<=19;j++) if (!(x&(1<<j))){
int y=x; y=y^(1<<i); y=y^(1<<j);
rec[sg[y]]=x;
break;
}
}
for (sg[x]=0;rec[sg[x]]==x;) sg[x]++;
}
int main(){
memset(sg,-1,sizeof(sg));
for (int i=0;i<=(1<<20)-1;i++) get_sg(i);
scanf("%d",&t);
while (t--){
sum=0;
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d",&m);
p=0;
for (int j=1;j<=m;j++){
scanf("%d",&x);
p|=1<<(x-1);
}
sum^=sg[p];
}
if (sum) printf("YES\n");
else printf("NO\n");
}
return 0;
}