数学: 博弈论. Nim游戏
C++
AcWing 891. Nim游戏
/* 题目描述: 891. Nim游戏: 给定 n 堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。 问如果两人都采用最优策略,先手是否必胜。 输入格式: 第一行包含整数 n。 第二行包含 n 个数字,其中第 i 个数字表示第 i 堆石子的数量。 输出格式: 如果先手方必胜,则输出 Yes。 否则,输出 No。 数据范围: 1 ≤ n ≤ 10^5, 1 ≤ 每堆石子数 ≤ 10^9 解题思路: 对于这种 Nim 游戏,首先需要考虑的是 必负态, 如果能让对手到达 必负态 的就是必胜态,否则就是必负态,加入必负态集合中。 从题目可知, n 堆石子全为 0 的状态就是必负态,本题不方便进行推导,我先给出公式后证明。 设 n 堆石子数量为 a1, a2, ..., an,倘若 a1 ^ a2 ^ ... ^ an = 0,表示先手必负,否则先手必胜。(其中 ^ 表示二进制异或) 证明: 1. 当 n 堆石子 全为 0,是必负态,满足 a1 ^ a2 ^ ... ^ an = 0 的条件。 2. 当 a1 ^ a2 ^ ... ^ an = x,并且 x != 0 时,我们来证明其是必胜态: a1 ^ a2 ^ ... ^ an = x 等式左侧,必定存在 ai,满足 x 的二进制最高位 1 在 ai 中也为 1。 那么可得 (ai ^ x) < ai。因此 a1 ^ a2 ^ ... ^ an = x 等式两侧同时异或上 x,可得 a1 ^ a2 ^ ... ^ an ^ x = 0 a1 ^ a2 ^ ... ^ (ai ^ x) ^ ... ^ an = 0 因此,我们在第 i 堆中可以拿出 ai - (ai ^ x)个石子,来使得剩余堆石子异或为 0 3. a1 ^ a2 ^ ... ^ an = 0条件下,我们拿出任意个石子,都不可能保持 异或 等于 0 的条件 假如说我们从第i堆取出一些石子(大于 0 ),数量从 ai 变为 bi ,我们假设异或仍旧等于 0 a1 ^ a2 ^ ... ^ ai ^ ... ^ an = 0 a1 ^ a2 ^ ... ^ bi ^ ... ^ an = 0 我们两式合并 (a1 ^ a2 ^ ... ^ ai ^ ... ^ an) ^ (a1 ^ a2 ^ ... ^ bi ^ ... ^ an) = 0 化简之后可得 ai ^ bi = 0,因此可以得到 ai = bi,然而 bi 是严格小于 ai 的,所以说假设不成立。 综上可知 a1 ^ ... ^ an = 0 为必负态,其余是必胜态。这是因为必胜态可以让对手达到必负态,必负态只能让对手达到必胜态 */ #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 100010; int a[N], n; bool solution() { int res = 0; for (int i = 1; i <= n; i ++ ) { res = (res ^ a[i]); } if (res == 0) { return false; } else { return true; } } int main() { scanf("%d", &n); for (int i = 1; i <= n; i ++ ) { scanf("%d", &a[i]); } if (solution()) { puts("Yes"); } else { puts("No"); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)