简单题意
n行20列的棋盘,两人轮流移动棋子,棋子只能向右移动一格,如果前面有阻碍,则可以跳过所有阻碍,直至不能移动,给出当前棋盘状态,问是否有必胜策略;
思路
博弈求SG值
把每一行独立考虑,则可以用一个20位的二进制数来表示棋盘状态,而且当先棋盘的状态的后继肯定比当前的数小(因为肯定有1的位置右移了),所以可以dp去求出从1 到1<<20的所有状态的SG值。
再对输入查表,得到每一行状态的SG值,全部异或起来即可得出结果
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1 << 20;
int ans[(1 << 20) + 10] = { 0 };
int has[25] = { 0 };
int main(){
for (int i = 1; i <= maxn; i++){
memset(has, 0, sizeof has);
for (int j = 0; j < 20; j++){
if (!(i & (1 << j)) && i & (1 << (j + 1))){
int t = i | (1 << j);
while (i & (1 << (j + 1))){
int s = t;
s ^= (1 << (j + 1));
has[ans[s]] = 1;
j++;
}
}
}
for (int k = 0; k < 25; k++){
if (!has[k]){
ans[i] = k;
break;
}
}
}
int T;
scanf("%d", &T);
while (T--){
int n; int res = 0;
scanf("%d", &n);
for (int i = 0; i < n; i++){
int num, loc, sta = 0;
scanf("%d", &num);
for (int k = 0; k < num; k++){
scanf("%d", &loc);
sta |= 1 << (20-loc);
}
res ^= ans[sta];
}
if (res) puts("YES");
else puts("NO");
}
}