[BZOJ 1115] [POI2009] 石子游戏Kam 【阶梯博弈】
题目链接:BZOJ - 1115
题目分析
首先看一下阶梯博弈:
阶梯博弈是指:初始有 n 堆石子,每次可以从任意的第 i 堆拿若干石子放到第 i - 1 堆。最终不能操作的人失败。
解法:将奇数位的石子堆做最基本的 NIM 就可以了。
WHY:对奇数位做 NIM 的必胜者总是可以胜利,因为如果从奇数位拿石子到偶数位,就相当于把这些石子拿走了,就是 NIM ;如果必败者从偶数位将石子拿到奇数位,必胜者总是可以将这些石子再向前移一个位置,就又放到了偶数位,这样一直移动的话,最终会是必胜者将这些石子拿到了 0 位置,然后必败者就不能再移动这些石子了。就相当于没有发生变化,偶数位的石子对我们的游戏就相当于没有影响。
然后看一下这道题,要求保证总是满足单调不降。
我们对石子进行差分,即 B[i] = A[i] - A[i - 1]。那么就会发现,从第 i 堆拿走一颗石子就是相当于将 B[i] -= 1, B[i + 1] += 1,那么就是一个向后进行的阶梯 NIM 了,从后向前取奇数位的 Bi 异或一下就可以了。
代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int MaxN = 1000 + 5; int T, n; int A[MaxN], B[MaxN]; int main() { scanf("%d", &T); for (int Case = 1; Case <= T; ++Case) { scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d", &A[i]); for (int i = 1; i <= n; ++i) B[i] = A[i] - A[i - 1]; int Temp = 0; for (int i = n; i > 0; i -= 2) Temp ^= B[i]; if (Temp) printf("TAK\n"); else printf("NIE\n"); } return 0; }