http://acm.hdu.edu.cn/showproblem.php?pid=5724
每行棋的格子有20个,用状态压缩,在0到1<<20间表示每种状态。之后记录该下一个棋子移动到的位置,移动每个棋子记录sg值。因为移动过程是变小的,所以必有sg值。
#include<iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int sg[(1<<20)+100];
void getSG()
{
int has[25];
int flag=-1,t;
sg[0]=0;
sg[1]=0;
for(int i=2; i<(1<<20); i++)
{
flag=-1;
memset(has,-1,sizeof(has));
for(int j=0; j<20; j++)
{
if(!((i>>j)&1))
{
flag=j;
}
if(((i>>j)&1))
{
if(flag!=-1)
{
has[sg[i^(1<<flag)^(1<<j)]]=1;
}
}
}
int j=0;
while(has[j]!=-1)
{
j++;
}
sg[i]=j;
}
}
int main()
{
getSG();
int T,n,ans,result,m,v;
scanf("%d",&T);
while(T--)
{
ans=0;
scanf("%d",&n);
for(int i=0; i<n; i++)
{
result=0;
scanf("%d",&m);
for(int k=0; k<m; k++)
{
scanf("%d",&v);
result^=1<<(20-v);
}
ans^=sg[result];
}
if(ans)
{
printf("YES\n");
}
else
{
printf("NO\n");
}
}
return 0;
}