[agc010d]Decrementing

前言

博弈题,还挺有趣。

题目大意

一个正整数序列,gcd为1。
两人轮流操作,每次选择一个>1的数将其-1。
然后d是新序列的gcd,将所有数除以d。
不能操作者输。

结论

初始gcd为1,一定存在至少一个奇数。
如果有奇数个偶数,先手是一定必胜的。
先手先操作一个偶数变成奇数(此时场上就至少2个奇数了,然后此时有偶数个偶数),然后看后手表演:
后手将一个奇数变成偶数,先手就再把这个偶数变成奇数。
后手将一个偶数变成奇数,先手可以把另一个偶数变成奇数。
可以发现中途任意时刻序列的gcd不会为偶数,因此不会改变序列每个元素的奇偶性。
这样下去先手就胜了。
那后手怎么胜呢?
有偶数个偶数吗?
似乎不太对,如果只有一个奇数的,先手就会上来先操作这个奇数,让场上出现偶gcd。
这种情况(偶数个偶数,且只有1个奇数)递归即可。
其余情况直接出解。

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
int a[maxn];
int i,j,k,l,t,n,m;
int gcd(int a,int b){
    return b?gcd(b,a%b):a;
}
bool solve(){
    int i;
    fo(i,1,n)
        if (a[i]%2==1){
            /*if (a[i]==1){
                if (n%2==0) return 1;
                else return 0;
            }*/
            if (a[i]==1) return 0;
            a[i]--;
            break;
        }
    int d=a[1];
    fo(i,2,n) d=gcd(d,a[i]);
    fo(i,1,n) a[i]/=d;
    int t=0,l=0;
    fo(i,1,n)
        if (a[i]%2==0) t^=1;else l++;
    if (!t&&l==1) return solve()^1;
    else if (t) return 0;
    else return 1;
}
int main(){
    scanf("%d",&n);
    fo(i,1,n){
        scanf("%d",&a[i]);
        k=a[i];
        if (k%2==0) t^=1;else l++;
    }
    if (!t&&l==1){
        if (solve()) printf("First\n");else printf("Second\n");
        return 0;
    }
    if (t) printf("First\n");else printf("Second\n");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值