此题就是一个sg函数的题目,需要找出每一行的sg值,然后异或就可以咯。
找sg需要在初始化的时候就找,也就是在t之前,暴力找出所有情况的sg。注意这个题只有20行,所以状态压缩一下就可以,每一行有棋子的地方就置为1,每一的地方就是0.
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int sg[(1<<21)+1];
int a[2005];
int vis[30];
int ans;
int n;
int maxx;
int SG(int x)
{
if(sg[x]!=-1)
return sg[x];
memset(vis,0,sizeof(vis));
for(int i=1; i<=20; i++)
{
if(x&(1<<i))
{
for(int j=i-1; j>=0; j--)
{
if((x&(1<<j))==0)
{
//printf("ssss");
// printf("sss%d %d %d\n",x,((1<<i)+(1<<j)),x^((1<<i)+(1<<j)));
//getchar();
vis[SG(x^((1<<i)+(1<<j)))]=1;
break;
}
}
}
}
for(int i=0;; i++)
{
if(vis[i]==0)
{
//printf("ssss");
sg[x]=i;
break;
}
}
//printf("sg[10]=%d\n",sg[10]);
return sg[x];
}
void init()
{
//cout<<(1<<21)-1<<endl;
memset(sg,-1,sizeof(sg));
sg[0]=0;
for(int i=1; i<=21; i++)
sg[(1<<i)-1]=0;
// printf("ssss%d\n",sg[3]);
// getchar();
for(int i=1; i<=2097151; i++)
{
//printf("ssss%d\n",i);
//getchar();
if(sg[i]==-1)
{
//printf("sssssssssss");
sg[i]=SG(i);
}
}
}
int main()
{
int t;
init();
//printf("ssss");
scanf("%d",&t);
while(t--)
{
ans=0;
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
int m;
scanf("%d",&m);
int sum=0;
maxx=(1<<m)-1;
// cout<<maxx<<endl;
for(int j=1; j<=m; j++)
{
int x;
scanf("%d",&x);
sum+=(1<<(20-x));
}
ans^=sg[sum];
}
if(ans)
printf("YES\n");
else
printf("NO\n");
}
}