题目大意:n行20列的棋盘,对于每行,如果当前棋子右边没棋子,那可以直接放到右边,如果有就跳过放到其后面的第一个空位子,A先操作,最后谁无法操作则输;
题目解析:只有20列,我们通过状态压缩得出序列传入sg函数,写的时候会发现需要把从左往右的序列倒过来,详细看代码;
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
const int N=1<<20;
int Hash[21];
int sg[1<<20];
int getSG(int l){
memset(Hash,0,sizeof(Hash));
for(int i=0;i<20;i++)
{
if(l&(1<<i))
{
for(int j=i+1;j<20;j++)
{
if(!(l&(1<<j)))
{
int temp=l;
temp^=((1<<i)^(1<<j));
Hash[sg[temp]]=1;
break;
}
}
}
}
for(int i=0;i<20;i++)
{
if(Hash[i]==0) return i;
}
}
int n;
int main()
{
memset(sg, 0, sizeof(sg));
for(int i = 0; i < (1 << 20); i++)
sg[i] = getSG(i);
int cas;
scanf("%d",&cas);
while(cas--)
{
//memset(sg,0,sizeof(sg));
int ans=0;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
int m,t=0;
scanf("%d",&m);
while(m--)
{
int u;
scanf("%d",&u);
t|=1<<(u-1);
}
ans^=getSG(t);
}
if(ans) printf("YES\n");
else printf("NO\n");
}
return 0;
}