HDU5724
题意:
一个 n * 20 的棋盘,棋盘上有若干棋子,Alice 和 Bob 轮流走,
每人每次可以选择任一行的一颗棋子向右移动到最近的一个空格 ;
也就是说如果右边与它相邻的格子里没有棋子,就移到右边与他相邻的格子去;
如果右边与它相邻的格子里 有棋子,就跳过它们移到相邻的空格 ;
一个空格只能放一颗棋子,且不能够放出去。
双方都采取最优策略,最后不能移动棋子的一方输 。
输入:
第一行输入 t ,表 t 组数据;
第二行输入 n ,表示 棋盘有 n 行;
接下来 n 行,每行包括 m (表示此行有 m 个棋子 )和 m 个数(棋子的位置)
输出:
若 Alice 赢,输出“YES” ,否则“NO”。
解题:
把它看成由 n 个子游戏组成的游戏, 那么整个游戏的 sg 值就是所有子游戏的 sg 值异或起来。
用二进制表示每一行的游戏局面 。 写完这题 感觉对状态压缩又多了解了一点点~~
(写的时候SB了一下,sg数组开小了= = 不造错哪又纠结了很久,不过也因为这样,想了很久这个问题,印象更深刻= =)
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> using namespace std; const int maxn = 1050000; int num[25],sg[maxn]; void getsg() { for(int i=1;i<(1<<20);i++) { int hash[50] = {0}, r=-1; for(int j=0;j<20;j++){ if( !((i>>j) & 1)) r = j; if( (i>>j) & 1){ if(r != -1) hash[ sg[i ^ (1<<j) ^ (1<<r)]] = 1; } } int j = 0; while(hash[j]!=0) j++; sg[i] = j; } } int main() { int t,n,m,loc; getsg(); scanf("%d",&t); while(t--){ scanf("%d",&n); int ans = 0; for(int i=0;i<n;i++){ scanf("%d",&m); num[i] = 0; for(int j=0;j<m;j++){ scanf("%d",&loc); num[i] ^= (1<<(20-loc)); } ans ^= sg[ num[i] ]; } printf(ans?"YES\n":"NO\n"); } return 0; }