Atcoder arc_105 D.Let‘s play Nim(博弈)

题意:给定你n个背包还有n个盘子,然后n个背包里第i个背包内放有a[i]个硬币,然后起初n个盘子都是空的,然后你可以进行的操作是,每一次选择一个背包然后将背包内所有的硬币放到一个盘子中,这个盘子可空可不空。当把所有的背包里的硬币都清空时,再从有硬币的盘子中,选择一个或多个硬币拿走,最后无法取硬币的人就输了,问是先手必胜还是后手必胜。

思路:题意都说了是nim那就往nim上考虑,首先n的数目是会决定我们后面进行拿硬币也就是nim的先手顺序,所以先分开考虑不同人先手的情况。
1.n为奇数,此时的话,是第二人先手开始nim游戏。从背包里那硬币的时候,无论第一个玩家把哪个包中的硬币放到了哪个盘子里,只要第二个玩家操作的时候,一直选取当前剩余的背包内硬币数最多的那个背包,把它放到第一个玩家第一次放得盘子中去,每次第二个玩家都这样操作,这样就能保证第二个玩家一直放得那个盘子的硬币数两是会 > 所有硬币数量的一半的,这样在开始nim游戏时,这几堆硬币的异或和一定是不为0的,所以先手的第二个玩家必胜。

2.再考虑n为偶数的情况,第一个玩家先手进行nim游戏,假如背包中的硬币数量的出现次数都是偶数的话,在这种情况下,第二个玩家每次拿硬币只需要去拿与第一个玩家拿的硬币数相等的那个背包即可,这样开始nim游戏时,所有硬币的异或和一定为零,先手必败。如果不是这种情况,那么第一个玩家也只需要每次都选择当前背包中,硬币数最多的那个背包放到同一个盘子里,这样最后nim游戏的异或和一定不为0,先手必胜。

想办法去考虑开始nim游戏的状态,从而转化为异或和解决。
一个堆中的石子数量大于所有堆的所有石子数量的一半,异或和一定不为0,因为如果一堆石子的数量大于一半的话,那么这堆石子数量的二进制中一定会有一位,和其他的不一样,故异或之后一定不为0。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 7;
int a[MAXN];
map<int,int>mp;

int main()
{
	int t;
	scanf("%d",&t);
	while(t--){
		mp.clear();
		int n;
		scanf("%d",&n);
		for(int i = 1;i <= n;i ++){
			scanf("%d",&a[i]);
			mp[a[i]]++;
		}
		if(n&1) puts("Second");
		else{
			int flag = 0;
			for(auto it = mp.begin();it != mp.end();it ++){
				if(it->second & 1){
					flag = 1;
					break;
				}
			}
			if(flag) puts("First");
			else puts("Second");
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值