1 条题解
-
0
思路与算法
这是正常玩法的Nim:每次只改变一堆,取任意正数,轮到时无石子者负。把所有堆大小异或得到 。 输出lose,否则输出win。只需逐项读入并累计异或,不必保存全部石子数。
异或逐位记录1的奇偶。非零时,找到 的最高非零位,在这一位为1的一堆 上改为 。最高位由1变0且更高位不变,因此 ,这是合法取走若干石子的操作,操作后全局异或变0。
正确性说明
全空局面的异或为0,且轮到者败。从异或0的局面改变一堆 为不同的 后,异或成为 ,无法一步保持零。反之,非零局面按最高位构造,总能合法走到异或0。
游戏总石子数每步严格减少,故没有循环或和局。对总石子数归纳,零异或局面的全部后继必胜,所以它必败;非零局面存在零异或败后继,所以它必胜。因此累计异或的判定及输出正确。
复杂度
累计量初始化 ,读入每堆做一次异或,共 时间;额外空间 。不按总石子数展开状态,也不保存全部堆。
易错点
- 每次只能取一堆,与同时改多堆、取光者输的版本不同。
- 异或不是按位或,也不是普通总和;相同堆成偶数对时异或抵消。
- 输出必须是小写win/lose。正式选点中堆初始大小均为正,空局面仅是策略证明的内部终态。
- 覆盖一堆、非零石子却零异或、最多50000堆及最大堆值。含初始零堆大小而违反当前源Xi≥1的公开整点已排除。
- 独立答案逐位统计奇偶,不调用异或判定,并与340个完整小规模极小化极大博弈核对。数据非官方原版。
参考代码(C++11)
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, value = 0; cin >> n; for (int i = 0; i < n; i++) { int pile; cin >> pile; value ^= pile; } cout << (value ? "win" : "lose") << '\n'; }
- 1