【博弈】AGC010D Decrementing

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/82841435

分析:

首先,有两个很显然的结论:
1、不考虑除以GCD的情况,就原问题而言(即只是-1),那么胜负只跟偶数的个数有关:若有偶数个偶数,那么后手必胜,反之先手必胜。
证明很简单:很容易想到,奇数的位置其实是可以忽略的,因为当某个人从奇数位-1,另一个人一定可以再在那里-1,又变为了奇数。偶数不能忽略,因为不一定偶数-1后还能再-1(可能就到1了,不能再-1)。所以每个偶数只需1次操作,就能变为奇数,既可以忽略。

换言之,这题就转化为:有N个石子,每次可以拿走一颗,求谁胜谁负。这就显然只跟石子的奇偶性有关了。

2、除以一个奇数,偶数的个数不变。

这证明就更简单了:奇数/奇数=奇数,偶数/奇数=偶数。

所以,其实只有两种情况:
1、直接根据偶数的个数分胜负。
2、尝试所有数除以2

但是,除以2是没那么容易的:
如果A除以2后,A必败,那A不可能去除以2。
如果A除以2后,B必败,那么B一定不会允许A除以2。

所以,除以2如果有效,那么必须在B无法影响的情况下,A一步就达到除以2的条件了。
换言之,只有当前状态有且仅有1个奇数(不为1)的情况下,并且除以2后能够使得对方必败。除以2才有效。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
typedef long long ll;
ll a[MAXN];
int n,now,cnt0,cnt1;
ll gcd(ll x,ll y){
	if(y==0)
		return x;
	return gcd(y,x%y);	
}
bool solve(){
	int cnt0=0,cnt1=0,now=0;
	for(int i=1;i<=n;i++){
		if(a[i]%2ll==0)
			cnt0++;
		else{
			cnt1++;
			now=i;
		}
	}
	if(cnt1==1&&a[now]!=1){
		ll g=0;
		a[now]--;
		for(int i=1;i<=n;i++)
			g=gcd(g,a[i]);
		for(int i=1;i<=n;i++)
			a[i]/=g;
		if(solve()==0)
			return 1;
	}
	if(cnt0%2==1)
		return 1;
	else
		return 0;
}
int main(){
	//freopen("game.in","r",stdin);
	//freopen("game.out","w",stdout);
	SF("%d",&n);
	for(int i=1;i<=n;i++)
		SF("%lld",&a[i]);
	if(solve())
		PF("First");
	else
		PF("Second");
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/82841435
今日推荐