Nim游戏(C++)

题目

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

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

输入格式

第一行包含整数 n。

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

输出格式

如果先手方必胜,则输出 Yes

否则,输出 No

数据范围

1≤n≤105,
1≤每堆石子数≤109

输入样例:

2
2 3

输出样例:

Yes

思路

输入所有的石子堆数目,若全部异或结果为0,则先手必败,否则先手必胜

证明:

定义:

必败态:拿到此状态的玩家,不论怎么操作都会输

必胜态:拿到此状态的玩家,总是可以通过一定的操作,使得下一次对手拿到的状态为必败态度。

在此题目中 假定a1 ....an都为0,则他们异或为0,此时为必败态,因为拿到这个状态的人无法操作。

反之如果异或值不是0,则可通过一定操作使得异或值为0。

证明非0态可以转化为0态(即必胜态可以留给对手必败态):

假定a1^a2^....an = x, x的二进制表示中最高一位1在第k位上

则a1~an中必有一个数ai,ai的第k位是1,得出结论ai ^ x < ai

我们再从ai中取得(ai - (ai ^ x))数目的石子

则ai中的石子数目为 ai - (ai - (ai ^ x))  = ai ^ x

所以现在式子变成a1^a2^...^ai^x^...^an

因为a1^....an = x

所以现在式子简化为x ^ x = 0 

局面已经是必败态了

证明0态必定转换到非0态(即拿到必败态的人留给对手的必定是必胜态)

反证法

假定现在拿到局势a1^a2^...an =0

我们对ai 操作成ai'

a1^a2^...^ai'^...an = 0

将两个等式异或一下发现

除了ai 和ai'不同,其他项完全相同,异或值为0,因此得到ai ^ ai' = 0

即ai = ai'

因此0态必定转换为非0态

代码

#include<iostream>

using namespace std;

int main()
{
	int n;
	cin >> n;
	
	int res = 0;
	while(n --)
	{
		int a;
		cin >> a;
		res ^= a; 
	}
	
	if(res)puts("Yes");
	else puts("No");
	
	return 0;
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值