「AcWing学习记录」博弈论
AcWing 891. Nim游戏
定理: Nim博弈先手必胜,当且仅当
\[a_1\wedge a_2\wedge\cdots \wedge a_n != 0
\]
问题1:当没有石子可拿的时候异或值为0,即
\[0\wedge 0\wedge\cdots \wedge 0 = 0
\]
问题2:当面临异或值不为0的局面时,一定可以从某堆石子中拿走一部分使剩下的石子异或值为0。
设
\[a_1\wedge a_2\wedge\cdots \wedge a_n = x != 0
\]
假设x的二进制表示中最高一位1在第k位,那么\(a_1\)~\(a_n\)中必然存在一个数\(a_i\)的第k位是1,且 \(a_i\wedge x < a_i\)。
又因为
\[a_i - (a_i - (a_i\wedge x)) = a_i\wedge x
\]
\[a_1\wedge a_2\wedge\cdots \wedge a_i\wedge x\wedge a_{i+1}\wedge\cdots \wedge a_n = x\wedge x = 0
\]
所以当从第i堆石子中拿走\(a_i - (a_i\wedge x)\)个石子时,可以使剩下的石子异或值为0。
问题3:当面临异或值为0的局面时,如果拿走一部分石子,一定会使剩下的石子异或值不为0。
利用反证法证明,假设当\(a_1\wedge a_2\wedge\cdots \wedge a_n = 0\)时,拿走一部分石子,剩下的石子异或值仍为0。
设\(a_i\)为第i堆石子原本的石子数,\(a_i'\)为拿走一部分石子后第i堆石子的石子数,则有
\[a_1\wedge a_2\wedge\cdots \wedge a_i\wedge a_{i+1}\wedge\cdots \wedge a_n = 0
\]
\[a_1\wedge a_2\wedge\cdots \wedge a_i'\wedge a_{i+1}\wedge\cdots \wedge a_n = 0
\]
将上下等式左右两边异或起来,有\(a_i\wedge a_i' = 0\),即 \(a_i = a_i'\),说明拿走前与拿走后的石子数相等,这与假设不相符,原命题成立。
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int n;
int res = 0;
scanf("%d", &n);
while(n--)
{
int x;
scanf("%d", &x);
res ^= x;
}
if(res) puts("Yes");
else puts("No");
return 0;
}
AcWing 892. 台阶-Nim游戏
AcWing 893. 集合-Nim游戏
AcWing 894. 拆分-Nim游戏