本题是经典 Nim 游戏 的变种。
核心思路
核心观察
本题基于经典 Nim 游戏,其胜负由所有石子堆数量的 异或和(XOR sum) 决定:
- 若异或和
,先手必胜;
- 若异或和
,先手必败。
小A在游戏开始前可执行一次特殊操作:从某一堆中恰好拿走 个石子 注意不是
(需满足该堆
),之后正常开始游戏(小A仍为先手)。
关键数学性质如下:
当原始异或和为 0 时,若存在某堆
且
,则操作后的新异或和为
由于
,必有
,因此该值
。
即:只要能合法执行一次操作(
且有堆足够大),小A就能将必败态转为必胜态。
此外:
- 若
,相当于无法改变局面;
- 若所有堆均
,也无法操作。
算法步骤
- 读入整数
(堆数)和
(可提前拿走的石子数)。
- 读入
个石子堆数量
,同时计算:
- 总异或和
total = a[0] ^ a[1] ^ ... ^ a[n-1] - 最大堆大小
mx = max(a[i])
- 总异或和
- 判断胜负:
- 若
total != 0:小A无需操作即可获胜 → 输出"YES"; - 否则(
total == 0):- 若
k == 0或mx < k:无法有效操作 → 输出"NO"; - 否则:存在合法操作使新局面异或和
→ 输出
"YES"。
- 若
- 若
正确性分析
-
情况一:原始异或和
小A作为先手,在标准 Nim 游戏中已有必胜策略,无需使用预操作。故输出"YES"正确。 -
情况二:原始异或和
- 若
:小A不能改变任何堆,局面不变,仍为必败态 →
"NO"正确。 - 若
:无一堆满足
,无法操作 →
"NO"正确。 - 若
且
:
设选中堆为,操作后该堆变为
。
新异或和为(因
),
小A作为新局先手,面对非零异或和,必胜 →"YES"正确。
- 若
| 条件 | 结果 | 说明 |
|---|---|---|
| 无法改变局面,仍必败 | ||
| 操作非法 | 无合法操作,必败 | |
| 必胜 |
综上,算法覆盖所有情况,逻辑严密。
复杂度分析
- 时间复杂度:
仅需一次遍历计算异或和与最大值。 - 空间复杂度:
存储石子堆数组;若边读边处理,可优化至额外空间。
数学逻辑推导
==命题 A==(平衡态不可维持) 若
,则任何合法操作都会使新异或和
。
==命题 B==(非平衡态可修复) 若
,则存在至少一个合法操作,使新异或和
。
证明命题 A:
任何操作导致 
设当前 。
玩家必须选择某堆 ,将其从
改为
,其中
(因至少取 1 个)。
新异或和为:
由于 ,必有
,因此:
==命题 A 得证==:从
出发,任何操作都会破坏平衡。
证明命题 B:
存在操作使 
设当前 。
令 为
的最高位 1 的位置(例如
,则
)。
因为 的第
位为 1,说明有奇数个堆在第
位为 1。
因此,至少存在一个堆 满足其第
位为 1。
对这个堆 ,定义:
我们验证:
(操作合法)
- 因为
的最高位是
,且
的第
位为 1,
所以会将
的第
位变为 0,而更高位不变,
故。
- 因为
- 新异或和为 0
命题 B 得证:从
出发,总能一步归零。
归纳论证:
是必败态
- 基础:终止状态
满足
,且当前玩家输。
- 归纳:
- 若当前
,由命题 A,玩家只能转移到
- 对手面对
,由命题 B,总能回到
- 如此循环,最终当前玩家将面对
而输
- 若当前
因此,所有
的状态都是必败态,
而
的状态都是必胜态。
在标准 Nim 游戏中:
- 若初始异或和
,先手必败,后手必胜;
- 若初始异或和
,先手必胜。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int n,k;cin>>n>>k;
vector<int>v(n);
int total=0,mx=0;
for(int i=0;i<n;i++){
cin>>v[i];
total^=v[i];//总异或值
mx=max(mx,v[i]);//堆里最大石子数量
}
if(total!=0){cout<<"YES";return 0;}
if(mx<k)cout<<"NO";
else if(k!=0)cout<<"YES";
else cout<<"NO";
}

京公网安备 11010502036488号