Nim游戏
题目
\(N\) 堆石子,两人轮流从其中一堆取至少一个石子,问先手是否存在必胜策略。
结论
异或不为0,先手必胜。
证明
设 \(k\) 为某一堆取完后的剩余个数,\(i\) 为被取那堆石子的编号,则取完后的异或和为 \(x_1\;xor\;x_2\;xor\dots xor\;x_{i-1}\;xor\;x_{i+1}\;xor\dots xor\;x_n\;xor\; k\)。
情况一:异或和为0
- 总数为0,此时先手输了
- 总数不为0,此时先手还要使异或和为0,就必须使得 \(k=x_i\),然而由于至少取一个,所以这是不可能的,所以必然会转为情况二。
情况二:异或和不为0
可以证明,必然可以取为0。
设 \(S=x_1\;xor\;x_2\;xor\dots xor\;x_n\),\(x_i\) 为 \(x\) 中的最大值。
- \(S\) 的二进制位数小于 \(x_i\) 的位数,则 \(x_i\) 必然可以凑出一个数使得其异或 \(S\) 等于0。
- \(S\) 的二进制位数和 \(x_i\) 的二进制位数相同,需满足 \(k\leqslant x_i\) 且 \(S\;xor\; x_i\;xor\;k=0\)。由于 \(S\;xor\; x_i\) 时已经使得二进制最高位为0,所以 \(k\) 的二进制最高位必然为0。\(k\) 在二进制的最高位已经满足小于 \(x_i\),后面的位数可以随便取,那么只需要取 \(S\;xor\; x_i\) 即可(这个数的二进制最高位也为0)。
代码
#include<bits/stdc++.h>
using namespace std;
int n, m, i, j, k, T;
int main()
{
scanf("%d", &n);
for(i=1; i<=n; ++i) scanf("%d", &k), m^=k;
printf(m ? "win" : "lose");
return 0;
}
本文来自博客园,作者:zhangtingxi,转载请注明原文链接:https://www.cnblogs.com/zhangtingxi/p/16004931.html