AtCoder Grand Contest 010D

来源:互联网 发布:ucloud云计算 2016 09 编辑:程序博客网 时间:2024/06/10 11:10

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");}
原创粉丝点击