台阶-Nim游戏
现在,有一个 $n$ 级台阶的楼梯,每级台阶上都有若干个石子,其中第 $i$ 级台阶上有 $a_i$ 个石子$(i \geq 1)$。
两位玩家轮流操作,每次操作可以从任意一级台阶上拿若干个石子放到下一级台阶中(不能不拿)。
已经拿到地面上的石子不能再拿,最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
输入格式
第一行包含整数 $n$。
第二行包含 $n$ 个整数,其中第 $i$ 个整数表示第 $i$ 级台阶上的石子数 $a_i$。
输出格式
如果先手方必胜,则输出 Yes 。
否则,输出 No 。
数据范围
$1 \leq n \leq {10}^5$ ,
$1 \leq a_i \leq {10}^9$
输入样例:
3 2 1 3
输出样例:
Yes
解题思路
结论是对于奇数的台阶如果$a_1 \oplus a_3 \oplus \ldots \oplus a_n \ne 0$,那么先手必胜,否则先手必败。
假设$a_1 \oplus a_3 \oplus \ldots \oplus a_n = x \ne 0$,根据Nim游戏的结论,一定可以通过拿走某堆的石子后(从奇数台阶拿到偶数台阶),剩下的奇数台阶石子的异或值为$0$,因此抛给对手的局面就变成$x = 0$了。
在对手的局面,此时$x = 0$,那么如果对手从偶数的台阶拿走石子放到奇数台阶,那么下一个局面我们就从这个奇数台阶拿同等数量的石子放到偶数台阶,这样的效果可以使得奇数台阶上的石子数量不变,抛给对手的局面始终是$x=0$。如果对手从奇数的台阶拿走石子放到偶数台阶,根据Nim游戏的结论剩下的奇数台阶石子的异或值一定不为$0$,即抛给我们的局面$x \ne 0$,那么一定可以通过某种方式使得$x = 0$,抛给对手的局面又变成了$x=0$。
因此我们总是可以保证对手的局面始终是$x = 0$的情况,由于终止局面所有的石子被拿完,奇数台阶的石子异或值为$0$,因此终止局面一定是会被对手遇到,因此后手必败。
还有一种理解方式,因为第$1$台阶的石子需要拿$1$次到地面,第$2$台阶的石子需要拿$2$次到地面,第$3$台阶的石子需要拿$3$次到地面,以此类推,因此可以理解为奇数台阶的每个石子有奇数堆,偶数台阶的每个石子有偶数堆,把石子拿到地面就变成了直接拿走,问题就变成了Nim游戏,直接异或起来,由于偶数台阶的石子均为偶数个,所以异或值为$0$,奇数台阶的石子均为奇数个,异或值就是本身,因此异或得到的结果就是原本奇数台阶石子的异或值。
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int main() { 5 int n; 6 scanf("%d", &n); 7 int ret = 0; 8 for (int i = 1; i <= n; i++) { 9 int x; 10 scanf("%d", &x); 11 if (i & 1) ret ^= x; 12 } 13 printf("%s", ret ? "Yes" : "No"); 14 15 return 0; 16 }
参考资料
AcWing 892. 台阶-Nim游戏:https://www.acwing.com/video/313/
标签:台阶,游戏,奇数,石子,偶数,异或,Nim From: https://www.cnblogs.com/onlyblues/p/17127941.html