题意:
给出n行,每行20列,放上若干个棋子,每个棋子只能移动到其右侧第一个空位,不能移动的lost
思路:
对于每行,有2^20种状态,虽然不多,但是存不下,因此要用位来压,1<<i表示了第20-i位数字是0 还是1,即棋子还是空。
对于每行来说,因为行是一个子问题,无法再次拆解,因此直接对于行来打sg函数的表。记录每个子问题的答案,异或便是最终答案
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1<<20;
int SG[maxn],f[maxn],vis[20];
void getSG()
{
memset(SG,0,sizeof(SG));
for(int s=0;s<(1<<20);++s)
{
memset(vis,0,sizeof(vis));
for(int i=19;i>=0;i--)
{
if(!(s>>i&1))
continue;
for(int j=i-1;j>=0;j--)
{
if(!(s>>j&1))
{
vis[SG[s^(1<<j)^(1<<i)]]=1;
break;
}
}
}
for(int i=0;i<=20;i++)
{
if(!vis[i])
{
SG[s]=i;
break;
}
}
}
}
int main()
{
getSG();
int t;
scanf("%d",&t);
while(t--)
{
int n,m,k;
scanf("%d",&n);
int res=0;
for(int i=0;i<n;i++)
{
scanf("%d",&m);
int s=0;
while(m--)
{
scanf("%d",&k);
s+=1<<20-k;
}
res^=SG[s];
}
if(res) puts("YES");
else puts("NO");
}
return 0;
}