Description
AKN玩游戏玩累了,于是他开始和同伴下棋了,玩的是跳棋!对手是wwx!这两位上古神遇在一起下棋,使得棋局变得玄幻莫测,高手过招,必有一赢,他们都将用最佳策略下棋,现在给你一个n*20的棋盘,以及棋盘上有若干个棋子,问谁赢?akn先手!
游戏规则是这样的:
对于一个棋子,能将它向右移动一格,如果右边有棋子,则向右跳到第一个空格,如果右边没有空格,则不能移动这个棋子,如果所有棋子都不能移动,那么将输掉这场比赛。
10%的数据T≤1,n≤1
另外10%的数据m≤1
100%的数据T≤100,n≤1000,m≤20,1≤pj≤20
By:Mul2016
Solution
显然每一行都是独立的,我们考虑求出每一行的sg
由于一定是20列,因此可以状压然后dfs预处理sg的值。然后就做完了
我才发现以前写的求sg函数的方法好像都是错的。由于桶是全局共用的,因此我们需要先求出后继状态的sg再取mex(具体看代码
Code
#include <stdio.h>
#include <string.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
const int N=1048578;
int rec[N],sg[N],n;
void get_sg(int x) {
if (~sg[x]) return ;
rep(i,0,19) if (x&(1<<i)) {
rep(j,i+1,19) if (!(x&(1<<j))) {
int y=x; y^=(1<<i); y^=(1<<j);
get_sg(y);
break;
}
}// 这里要分开来写,以前都是合起来的╮(╯▽╰)╭
rep(i,0,19) if (x&(1<<i)) {
rep(j,i+1,19) if (!(x&(1<<j))) {
int y=x; y^=(1<<i); y^=(1<<j);
rec[sg[y]]=x;
break;
}
}
for (sg[x]=0;rec[sg[x]]==x;) sg[x]++;
}
int main(void) {
fill(sg,-1);
rep(i,0,(1<<20)-1) get_sg(i);
int T; for (scanf("%d",&T);T--;) {
int n,sum=0; scanf("%d",&n);
rep(i,1,n) {
int m,p=0; scanf("%d",&m);
rep(j,1,m) {
int x; scanf("%d",&x);
p|=1<<(x-1);
}
sum^=sg[p];
}
puts((!sum)?"NO":"YES");
}
return 0;
}