【HDU5724 2016 Multi-University Training Contest 1B】【博弈 SG函数】Chess 棋子跳棋向右移 先后手胜负博弈
2016-07-25 09:46
417 查看
Chess
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1369 Accepted Submission(s): 597
[align=left]Problem Description[/align]
Alice and Bob are playing a special chess game on an n × 20 chessboard. There are several chesses on the chessboard. They can move one chess in one turn. If there are no other chesses on the right adjacent block of the moved
chess, move the chess to its right adjacent block. Otherwise, skip over these chesses and move to the right adjacent block of them. Two chesses can’t be placed at one block and no chess can be placed out of the chessboard. When someone can’t move any chess
during his/her turn, he/she will lose the game. Alice always take the first turn. Both Alice and Bob will play the game with the best strategy. Alice wants to know if she can win the game.
[align=left]Input[/align]
Multiple test cases.
The first line contains an integer T(T≤100),
indicates the number of test cases.
For each test case, the first line contains a single integer n(n≤1000),
the number of lines of chessboard.
Then n lines,
the first integer of ith line is m(m≤20),
indicates the number of chesses on the ith line of the chessboard. Then m integers pj(1≤pj≤20)followed,
the position of each chess.
[align=left]Output[/align]
For each test case, output one line of “YES” if Alice can win the game, “NO” otherwise.
[align=left]Sample Input[/align]
2
1
2 19 20
2
1 19
1 18
[align=left]Sample Output[/align]
NO
YES
[align=left]Author[/align]
HIT
[align=left]Source[/align]
2016 Multi-University Training
Contest 1
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } #define MS(x,y) memset(x,y,sizeof(x)) #define MC(x,y) memcpy(x,y,sizeof(x)) #define MP(x,y) make_pair(x,y) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; } const int N = 0, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f; int casenum, casei; int n, m; int b[24]; int sg[1 << 20]; int no[24]; void init() { for (int i = 0; i < 20; ++i)b[i] = 1 << i; int top = 1 << 20; for (int i = top - 1; ~i; --i) { MS(no, 1); int blk = -1; for (int j = 19; ~j; --j) { if (i >> j & 1) { if (~blk) { int nxt = i ^ b[j] ^ b[blk]; no[sg[nxt]] = 0; } } else blk = j; } while (!no[sg[i]])++sg[i]; } } int main() { init(); scanf("%d", &casenum); for (casei = 1; casei <= casenum; ++casei) { scanf("%d", &n); int SG = 0; for (int i = 1; i <= n; ++i) { int g; scanf("%d", &g); int sta = 0; while (g--) { int x; scanf("%d", &x); --x; sta |= b[x]; } SG ^= sg[sta]; } puts(SG ? "YES" : "NO"); } return 0; } /* 【题意】 n*20的棋盘 每行有若干个棋子。 A和B轮流做游戏。 每次可以任选一行,把该行的某个棋子按照一定的规则移动。 最后谁不能移动就输了。 问先手胜负情况。 移动规则是这样的—— 如果选定棋子右侧为空,则直接移过去。 否则把该棋子移动至右侧非空的第一个位置。 【类型】 博弈 SG函数 【分析】 这题对于每行,显然都可以认定为一个独立的子游戏。 行状态最多只有2^20,我们对其做个SG函数预处理。 然后把所有行的SG值异或起来,非零则先手必胜。 问题是——如何求SG值呢? 我们发现—— 1,棋子只会往右移动,如果我们把b[i]定义为1<<i的话,右移操作只会使得状态编号越变越大。 ——于是我们按照状态数由大到小的顺序处理SG函数 2,每个状态的后继状态最多只有20个,这意味着 ——我们可以快速算出SG函数,且SG函数的值限定在[0,20]之间 【时间复杂度&&优化】 O(1 << 20 * 20) */
相关文章推荐
- [FAFU 1292]博弈论,组合游戏,取石游戏
- Sicily 1305 Who’s Winner?
- 三种类型博弈(bash + nimm +wythoff)
- Andrew Stankevich Contest 38 , J-Jackpot
- 纸牌博弈问题
- HDU1527 纯威左夫博弈
- uva 12293 Box Game
- hdu 1846 (博弈)
- HDU 1849(尼姆博弈)
- hdu 1847(博弈)
- hdu 1850(妮姆博奕)
- HDU 1079 Calendar Game
- cf 276b 博弈
- Hdu2177-博弈(Sg函数找规律)
- SG-分石子游戏
- 博弈-取石子
- 博弈-威佐夫博弈
- 博弈-巴什博弈
- 博弈-Nim博弈
- 取石子游戏 (HDU_256) 斐波拉契 博弈