台阶-Nim游戏

台阶-Nim游戏

现在,有一个 n 级台阶的楼梯,每级台阶上都有若干个石子,其中第 i 级台阶上有 ai 个石子(i1)

两位玩家轮流操作,每次操作可以从任意一级台阶上拿若干个石子放到下一级台阶中(不能不拿)。

已经拿到地面上的石子不能再拿,最后无法进行操作的人视为失败。

问如果两人都采用最优策略,先手是否必胜。

输入格式

第一行包含整数 n

第二行包含 n 个整数,其中第 i 个整数表示第 i 级台阶上的石子数 ai

输出格式

如果先手方必胜,则输出 Yes 。

否则,输出 No 。

数据范围

1n105 ,
1ai109

输入样例:

3
2 1 3

输出样例:

Yes

 

解题思路

  结论是对于奇数的台阶如果a1a3an0,那么先手必胜,否则先手必败。

  假设a1a3an=x0,根据Nim游戏的结论,一定可以通过拿走某堆的石子后(从奇数台阶拿到偶数台阶),剩下的奇数台阶石子的异或值为0,因此抛给对手的局面就变成x=0了。

  在对手的局面,此时x=0,那么如果对手从偶数的台阶拿走石子放到奇数台阶,那么下一个局面我们就从这个奇数台阶拿同等数量的石子放到偶数台阶,这样的效果可以使得奇数台阶上的石子数量不变,抛给对手的局面始终是x=0。如果对手从奇数的台阶拿走石子放到偶数台阶,根据Nim游戏的结论剩下的奇数台阶石子的异或值一定不为0,即抛给我们的局面x0,那么一定可以通过某种方式使得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/

posted @   onlyblues  阅读(70)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2022-02-16 二分求解最值问题例题
Web Analytics
点击右上角即可分享
微信分享提示