AtCoder Grand Contest 010D

vjudge传送门
题目大意:
给一个GCD为1的数列,有两个人每次选出一个数把这个数-1,然后把整个数列除以新数列的GCD,询问先手和后手哪个必胜。

Solution:
不难看出这是一道博弈论,我们可以假设没有GCD的限制,那么我们怎么做呢?求数列的sum然后判断sum-n的奇偶性就可以了。类比上述情况,当这个数列全是奇数时,每次操作必然会产生一个偶数,由于新数列的GCD一定是奇数,所以说GCD并不会影响数列的值的奇偶性,所以说如果初始数列全是奇数的话,那么后手必胜,策略很简单:先手改出一个偶数,后手再把它改回去,如此往复,先手必输。
既然我们知道只有一个偶数的话先手必赢,那么类比一下,有奇数个偶数的话也会是先手必赢么?是的。证明也是很简单,在一个数上纠结奇偶显然和只有一个奇数的情况一样,如果先手后手的操作都是把偶数-1的话那么最后一个偶数一定是先手减掉的。同理,如果有偶数个偶数的话后手必胜。
然后这个题就做完了

才怪
我们还要考虑一个特殊情况:只有一个奇数,其余是偶数个偶数,这种情况先手可以不先选偶数,反而去选择那一个奇数,这样的话数列一定会产生一个大于一的GCD,我们递归的对这个数列进行处理即可。

AC代码:

#include<cstdio>
#include<iostream>
using namespace std;
int a[100010];
int n;
int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
bool dg()
{
    long long sum=0;
    bool ex=0;
    int num=0;
    for (int i=1;i<=n;i++)
    {
        sum+=a[i]-1;
        if (a[i]&1) num++;
        if (a[i]==1) ex=1;
    }
    if (ex) return sum%2;
    if ((n-num)%2) return 1;
    if (num==1)
    {
        int g=0;
        for (int i=1;i<=n;i++)
            if (a[i]&1) a[i]--;
        for (int i=1;i<=n;i++)
            g=gcd(g,a[i]);
        for (int i=1;i<=n;i++)
            a[i]/=g;
        return dg()^1;
    }
    return 0;

}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    if (dg()) printf("First");
        else printf("Second");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值