题目描述
给定n堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
输入格式
第一行包含整数n。
第二行包含n个数字,其中第 i 个数字表示第 i 堆石子的数量。
输出格式
如果先手方必胜,则输出“Yes”。
否则,输出“No”。
数据范围
1≤n≤105,
1≤每堆石子数≤109
样例
输入样例:
2
2 3
输出样例:
Yes
Nim游戏:
题目:给定n堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败
问如果两人都采用最优策略,先手是否必胜
(无论后手怎么操作,先手都从另一堆里做镜像操作,就是说,只要对手有石子拿,我就一定也有石子拿,因为我可以保证我拿完石子后两堆石子时时刻刻一样,所以说,一定是对手会先遇到0,0点这个状态,那么对手就必输,先手就必胜)
2 3--> 2 2 所以后手一定会先走到0 0这个状态,先手就必赢
先手:
必败(状)态:0 0 不管我怎么操作,剩下的状态都是必胜状态,就是都是对手赢
必胜(状)态:就是说,我拿完之后可以让剩下的状态是一个必败状态,那么我就是必胜状态
nim
定理: n堆石子a1,a2,……an
a1^a2^……^an=0先手必败
a1^a2^……^an!=0先手必胜
证明:
1. !=0 --(变成)-> =0;
如果所有数异或起来不等于零,一定存在某种方式使得所有数异或起来等于零
2. 如果所有数异或起来等于零,无论怎么拿,异或后都不等于零
C++ 代码
#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;
}