原题:hdu 5724
题意:
有n行棋盘 , 每行20列 , 你可以选择一行进行操作 , 选择一个棋子移动到右边的第一个空位 , 不能操作的人lost
解析:
用打表预处理SG函数 , 注意vis只需要50就可以了(我不小心开了10000一直TLE , QAQ) , 最后异或一下为0必输不为0必胜
#include<bits/stdc++.h>
using namespace std;
int read(){ int ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
const int N=(1<<20)-1;
int sg[N+2];
bool vis[50];
void init(){
memset(sg,0,sizeof(sg));
for(int i=2;i<=N;i++){
memset(vis,0,sizeof(vis));
int x=i;
int bit[22],now=0;//先存下可以节省时间
while(x){
bit[++now]=x%2;
x/=2;
}
int last=-1;
for(int j=1;j<=now;j++){
if(bit[j]){
if(last!=-1)
vis[sg[i-(1<<(j-1))+(1<<(last-1))]]=1;
}
else last=j;
}
for(int j=0;;j++){
if(!vis[j]){sg[i]=j;break;}
}
}
}
int main(){
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
init();
int t=read();
while(t--){
int n=read();
int A=0;
while(n--){
int m=read();
int x=0;
while(m--){
int tmp=read();
x+=1<<(20-tmp);
}
A^=sg[x];
}
if(A==0)printf("NO\n");
else printf("YES\n");
}
}