题目大意:有一个n*20的棋盘,每一行有若干个棋子,每个棋子可以移动到它右边离它最近第一个空格里,两个人轮流移动,直到有一方不能移动为输。问是否存在先手必胜策略。
分析:棋盘的各个行之间是相互独立的,预处理出0~(1<<20)-1的sg函数,然后对于每一行的状态求出该状态对应的sg函数值,进行异或操作即可。
#include <cstdio>
#include <cmath>
#include <iostream>
#include<ctime>
#include<cstdlib>
using namespace std;
int n;
int sg[1100000];
int h[20];
int dfs(int x)
{
for (int i=0;i<20;i++) h[i]=0;
for (int i=0;i<20;i++)
{
if (x&(1<<i))
{
for (int j=i+1;j<20;j++)
{
if (!(x&(1<<j)))
{
h[sg[x^(1<<i)^(1<<j)]]=1;
break;
}
}
}
}
for (int i=0;i<20;i++)
if (!h[i]) return i;
}
int main()
{
int t;
scanf("%d",&t);
for (int i=(1<<20)-1;i>=0;i--) sg[i]=dfs(i);
while (t--)
{
int n;
scanf("%d",&n);
int ans=0;
for (int i=0;i<n;i++)
{
int q;
scanf("%d",&q);
int m=0;
while (q--)
{
int x;
scanf("%d",&x);
m=m | (1<<(x-1));
}
ans=ans^sg[m];
}
if (ans) printf("YES\n");
else printf("NO\n");
}
return 0;
}