agc010 D - Decrementing

Problem Statement
There are N integers written on a blackboard. The i-th integer is Ai, and the greatest common divisor of these integers is 1.

Takahashi and Aoki will play a game using these integers. In this game, starting from Takahashi the two player alternately perform the following operation:

Select one integer on the blackboard that is not less than 2, and subtract 1 from the integer.
Then, divide all the integers on the black board by g, where g is the greatest common divisor of the integers written on the blackboard.
The player who is left with only 1s on the blackboard and thus cannot perform the operation, loses the game. Assuming that both players play optimally, determine the winner of the game.

Constraints
1≦N≦105
1≦Ai≦109
The greatest common divisor of the integers from A1 A 1 through AN A N is 1.

题目大意

给出n个整数,然后轮流操作:
选取一个数减一,
然后所有数除以它们的最大公约数。
1不能被减一,
无法操作者输。
一开始的最大公约数为1。

题解

考虑先手什么时候可以获胜,
倒推一下就知道如果当前先手的序列是1,1,1…1,2
很显然,将2减一之后就获胜了。
延伸一下,假设先手的序列是:x,x,x…x,x+1
那他的操作就是将x+1减一,
然后全部除以x,获胜。

考虑最大公约数为1的情况,
就是说在除以最大公约数的这个步骤里面,所有的数都不改变,
也就是说他们的奇偶性也不会发生改变。

如果奇偶性是先手胜,
那么先手的任务就是使得最大公约数保持为1,
如果奇偶性对先手不利,
改变奇偶性的唯一办法就是整体除上一个数。

code

#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 100003
#define M 103
#define db double
#define P putchar
#define G getchar
#define inf 998244353
using namespace std;
char ch;
void read(int &n)
{
    n=0;
    ch=G();
    while((ch<'0' || ch>'9') && ch!='-')ch=G();
    ll w=1;
    if(ch=='-')w=-1,ch=G();
    while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
    n*=w;
}

int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}

int n,a[N],ans,s;
bool pd; 

int gcd(int x,int y){return y==0?x:gcd(y,x%y);}

bool dfs(int x)
{
    s=pd=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==1)pd=1;
        if(a[i]&1)s++;
    }

    if((n-s)&1)return x;
    if(pd || s>1)return !x;

    for(int i=1;i<=n;i++)
        if(a[i]%2)
        {
            a[i]--;
            break;
        }

    int gc=a[1];
    for(int i=2;i<=n;i++)
        gc=gcd(gc,a[i]);
    for(int i=1;i<=n;i++)
        a[i]/=gc;
    return dfs(!x);
}

int main()
{
    read(n);
    for(int i=1;i<=n;i++)
        read(a[i]);

    if(dfs(1))puts("First");
        else puts("Second");

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值