题目:(最简单的博弈论)
给定 n堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
输入格式
第一行包含整数 n。
第二行包含 n个数字,其中第 i个数字表示第 i 堆石子的数量。
输出格式
如果先手方必胜,则输出 Yes
。
否则,输出 No
。
数据范围
1≤n≤10^5,
1≤每堆石子数≤10^9
输入样例:
2
2 3
输出样例:
Yes
(题目摘自www.acwing.com)
题解思路:
当先手面临,所有石子堆全部变为0的状态时,此时先手必败,所以定义如果先手能够走到一个必败的状态时,称其为先手必败状态,反之为先手必胜状态。
本题利用一个既定的结论,在这里不做证明(利用异或进行求解,很难想到),一共有n堆石子,从a1,a2,a3……an.一共存在两种情况:
a1^a2^a3……^an=0(先手必败)
a1^a2^a3……^an≠0(先手必胜)
异或:两个二进制数,相同位相同为0,不同为1。
证明:
①:0^0^0^……0=0,第一种情况很明显可以看出为0。
②:a1^a2^a3……^an=x≠0,这种情况,x的二进制表示中最高一位的1在第k位,则a1到an中必定存在一个ai,ai的第k位为1,则ai^k<ai。
在这里举一个例子,ai:11001001101,x为00001010010,则ai^x必定小于ai。
则从第ai堆石子中取走ai-(ai^x)个,ai堆石子剩余ai^k个石子,则取完以后:
a1^a2^……ai^k^ai+1……^an=x^x=0,所以说明当a1^a2^a3……^an=x≠0时,先手总可以取走若干个石子,使得后手处于a1^a2^a3……^an=0的状态,直到游戏即将结束时,先手取走若干的石子,此时后手必定面临0^0^0^……0=0的状态,则先手必胜。
③:a1^a2^a3……^an=0,这种情况下,先手遇到的为0,抛给后手的一定不为0,所以最终
0^0^0^……0=0的状态一定会被先手遇到,所以先手必败,所以可以有以上的结论。
所以可以有以下代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;scanf("%d",&n);
int res=0;
while(n--)
{
int x;scanf("%d",&x);
res^=x;
}
if(res)puts("Yes");
else puts("No");
return 0;
}