原题链接
给定n堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。

问如果两人都采用最优策略,先手是否必胜。

输入格式
第一行包含整数n。

第二行包含n个数字,其中第 i 个数字表示第 i 堆石子的数量。

输出格式
如果先手方必胜,则输出“Yes”。

否则,输出“No”。

数据范围
1≤n≤105,
1≤每堆石子数≤109
输入样例:
2
2 3
输出样例:
Yes

先上一波代码

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n;
	int res=0;
	cin>>n;
	while(n--){
		int x;
		cin>>x;
		res^=x;
	}
	if(res) cout<<"Yes"<<endl;
	else cout<<"No"<<endl;
	
	return 0;
} 

该题为简单的 博弈论题目,一般博弈论题目有如下特征:

1.有两名选手;

2.两名选手交替操作,每次一步,每步都是在有限的合法集合中选取一种进行;

3.在任何情况下,合法操作只取决于情况本身,与选手无关;

4.游戏的败北条件为:当某位选手需要进行操作时,当前没有任何可以执行的合法操作,则该选手败北。

先来介绍Nim里的两种状态,先手必败状态和先手必胜状态。
前者是先手走不到任何一个必败状态,即后手无法是必败状态,先手必败。
后者即先手可以走到某个必败状态,此时为后手操作,后手必败。

Nim游戏中有个经典结论:若a1^a2…an==0 则先手必败。

我们可以从简单的数据入手,比如有两堆石子的数量分别为2、3。那么是不是先手必胜呢。我们可以先用结论及代码验证一下。

#include<bits/stdc++.h>
using namespace std;
int main(){
	int a1 = 2 , a2 = 3 ;
	if(a1^a2==0) puts("Win");
	else puts("Lose");
	return 0;
}

运行结果如图

那么我们现在可以模拟一下具体过程,前提是每个人每一步都是最优策略。先手从石子数为3的堆里取走一个石子,此时变为2 2,接下来不论后手做任何操作,先手只需在另一堆石子里做相同的操作,这样就再次使得两堆石子的数目一样。如此循环下去,一定是后手遇到必败状态,先手胜利。
接下来进行简单的证明一下:
首先,当所有的堆的石子数均为0时,异或值也是0,即不能进行任何操作,先手必败。
然后,如果异或值不为零,即a1^a2…an= k(k为非零常数),先手一定可以某种操作(即从某堆石子中拿走部分石子)让异或值变为0,此时后手走到了必败态,先手必胜。(具体为什么是异或值还有待探索)
假设k的二进制表示中最高的一位1是第x位, 那么在a1-an中必存在有一个数ai的第x位是1;那么ai^x<ai(ai的第k位由1变为0),我们可以从ai个石子中拿走ai-ai ^x 个石子(操作一定合法),这样的话所有的数的异或值就是0。
最后,我们来证明如果a1^a2…an=0,无论如何拿,所有数的异或值一定不是0。反证法可证。

具体为什么是异或值为0,可以参考K-Nim游戏;

Nim还有很多变形,学习中。
扔一道台阶Nim的题吧 惊奇队长和灭霸的决战 来自临沂大学新生赛
蓝桥杯历年试题 高僧斗法 也是如此
最后放一篇写的很好的高僧斗法的题解

不当之处,请多指教。