Nim 博弈:把各堆石子数按位异或,先手必胜当且仅当异或和(Nim 和)非零,O(N) 判定。
OJ: roj
题目 ID: 1664
难度:普及
标签:博弈论数学
创建: 2026-10-01 00:46
更新: 2026-10-07 13:50
题目描述
有 win,后手获胜输出 lose。
输入:第一行一个整数 win 或 lose。
数据范围:4 与 7 12 9 15,样例输出 win。
思路
这是经典 Nim 博弈,由 Bouton 定理:把
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-01 00:46
# update_at: 2026-10-01 00:46
import sys
from functools import reduce
from operator import xor
def solve() -> None:
"""Nim 博弈:先手必胜当且仅当各堆石子数的异或和不为 0。"""
data = iter(sys.stdin.buffer.read().split())
n = int(next(data))
piles = [int(next(data)) for _ in range(n)]
nim_sum = reduce(xor, piles) # Nim 和:把每堆数量按位异或起来
print("win" if nim_sum else "lose")
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-06 01:45
* update_at: 2026-10-06 01:45
*/
#include <cstdio>
typedef long long ll;
ll n; // 石子堆数
ll x; // 当前读入的一堆石子数
ll s; // Nim 和:全部堆数的按位异或
int main() {
scanf("%lld", &n);
s = 0;
for (ll i = 1; i <= n; i++) {
scanf("%lld", &x);
s ^= x; // 边读边异或,无需保存每堆数量
}
// Bouton 定理:Nim 和不为 0 先手必胜,为 0 先手必败
if (s != 0)
printf("win\n");
else
printf("lose\n");
return 0;
}