【AtCoder2305】Decrementing(博弈)

本文探讨了一个数学游戏的胜负策略,游戏中两名玩家轮流操作,通过减少黑板上数字并调整其最大公约数来决定胜负。文章详细解析了不同状态下游戏的胜负情况,并提供了实现算法的代码。

题意

黑板上有n个数,它们的最大公约数为1.于是A和B决定玩一个游戏,两个人轮流进行操作,A先手。
从黑板上的数选择一个不小于2的数,把这个数减去1,然后对于这n个数,除以他们的最大公约数.
当一个人无法操作时便输了。求先手是否必胜。

题解

定义状态1:有奇数个偶数,奇数至少一个
定义状态2:有偶数个偶数,且奇数个数≥2
定义状态3:有偶数个偶数,奇数一个

所有数都为1,为必败态,属于状态2
状态2,无论选哪一个数操作,gcd都不为偶数,操作后,偶数个数-1,只能转移到状态1
而状态1保证可以操作后转为状态2,所以状态2为必败态

状态3,如果选择偶数操作,转换为状态2,必败。选择奇数,继续递归求解。

代码

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=100005;

int n,A[MAXN];

bool solve()
{
	if(n==1)
		return false;
	int cnt[2]={0,0};
	for(int i=1;i<=n;i++)
		cnt[A[i]&1]++;
	if(cnt[0]&1)
		return true;
	if((cnt[0]&1)==0&&cnt[1]>=2)
		return false;
	int pos=-1;
	for(int i=1;i<=n&&pos==-1;i++)
		if(A[i]&1)
			pos=i;
	if(A[pos]==1)
	{
		int sum=0;
		for(int i=1;i<=n;i++)
			sum^=(A[i]-1)&1;
		return sum;
	}
	A[pos]--;
	int g=A[1];
	for(int i=2;i<=n;i++)
		g=__gcd(g,A[i]);
	for(int i=1;i<=n;i++)
		A[i]/=g;
	return solve()^1;
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&A[i]);
	if(solve())
		puts("First");
	else
		puts("Second");
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CaptainHarryChen

随便

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值