agc 010Decrementing atcoder2305

http://www.elijahqi.win/archives/1425
Time limit時間制限 : 2sec / Memory limitメモリ制限 : 256MB

配点 : 1000 点

問題文
黒板に N 個の整数が書かれています。i 番目の整数は Ai であり、これらの最大公約数は 1 です。

高橋君と青木君はこの数を使ってゲームをします。ゲームでは高橋君から始めて交互に以下の操作を繰り返します。

黒板の中から 2 以上の数を 1 つ選び、その数から 1 を引く。
その後、黒板に書かれた数の最大公約数を g として、すべての数を g で割る。
黒板に書かれた数が全て 1 となっていて、操作が行えない人の負けです。 二人が最適に行動したとき、どちらが勝つか求めてください。

制約
1≦N≦105
1≦Ai≦109
A1 から AN の最大公約数は 1
入力
入力は以下の形式で標準入力から与えられる。

N
A1 A2 … AN
出力
先手の高橋君が勝つなら First を、後手の青木君が勝つなら Second を出力せよ。

入力例 1
Copy
3
3 6 7
出力例 1
Copy
First
以下のようにすれば先手の高橋君が勝てます。

高橋君が 7 から 1 を引く。このとき、操作後は (1,2,2) となる。
青木君が 2 から 1 を引く。このとき、操作後は (1,1,2) となる。
高橋君が 2 から 1 を引く。このとき、操作後は (1,1,1) となる。
入力例 2
Copy
4
1 2 4 8
出力例 2
Copy
First
入力例 3
Copy
5
7 8 8 8 8
出力例 3
Copy
Second
Score : 1000 points

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 through AN is 1.
Input
The input is given from Standard Input in the following format:

N
A1 A2 … AN
Output
If Takahashi will win, print First. If Aoki will win, print Second.

Sample Input 1
Copy
3
3 6 7
Sample Output 1
Copy
First
Takahashi, the first player, can win as follows:

Takahashi subtracts 1 from 7. Then, the integers become: (1,2,2).
Aoki subtracts 1 from 2. Then, the integers become: (1,1,2).
Takahashi subtracts 1 from 2. Then, the integers become: (1,1,1).
Sample Input 2
Copy
4
1 2 4 8
Sample Output 2
Copy
First
Sample Input 3
Copy
5
7 8 8 8 8
Sample Output 3
Copy
Second
代码好写 不好想 %%visjiao %%yutaka1999%%leoly

数列的话一定有必胜的情况 比如sum为奇数n为偶数 sum为偶数n为奇数都是必胜的 sum为奇数n为偶数是必输的

n为奇数sum为奇数需要讨论(必胜必输指先手必胜必输)

强啊visjiao题解非常全就抄过来了

题意简述
给出一个n(n≤105) 个数的序列a ,足够聪明的AB两人轮流进行以下操作:
令一个大于1的数减1,然后所有数除以gcd{a} 。
如果一个人不能操作了,那么他就输了。
输入保证所有数都是正整数并且gcd{a}=1 。

分析
这是一道和奇偶性有关的题目。
很容易知道拿到1,1,1,…,1 就输了,此时手里数的和sum 等于n 。

考虑sum 奇偶性的转换关系。

或者再展开一点:

偶-奇 是必然的很好理解,重点考虑一下sum 为奇数的情形。
奇(-偶)-奇 要求gcd为偶数,因为偶/奇=偶。因此原数列%2必然是000…01的形式,而我可以将其变为000…11从而形成奇-偶 。所以奇-奇 是一定条件下可选的,奇-偶 是任何条件下可行的。

由此再考虑n 的奇偶性对答案的影响。

n 为偶数
能保持sum 为奇数的一方一定不会输。既然sum 一直是奇数,那么就一定不会得到1,1,1,…,1 的状态,必胜。而因为拿到奇数的一方一定可以给对手一个偶数,而对手只能无可奈何地还你一个奇数。所以初始sum 为奇数则先手必胜,否则必败。
时间复杂度为O(n) 。
n 为奇数
能保持sum 为偶数的一方一定不会输。但是拿到偶数的一方需要保证对手不会还回来一个奇数,下面证明这一点一定可以做到。
证明

首先奇数方要是想还给对手一个奇数必然要使gcd不为1,所以原数列%gcd必然是000…01的形式。再考虑这个状态是怎么达到的:

对于000…11,000…02,000…1k,000…0(k+1)这四种状态另一方都有办法规避000…01的结果。所以拿到偶数的一方一定能保证下一轮自己还是偶数。
因此初始sum 为偶数的话先手必胜。
时间复杂度为O(n) 。

但是初始sum 是奇数并不意味着必败;因为此时还没有另一方的干扰,是有可能给对手一个奇数的。但是由于你可能只有极少的选择方案,这给了对手可乘之机:对手也有可能还回来一个奇数。以此循环往复,无法给对手奇数的一方会输掉游戏。
因为每次都会给所有数除以一个大于1的gcd,所以最多往复log2(min{a}) 次,其中每次操作的复杂度是O(n) 。时间复杂度最大为O(n⋅log2(min{a})) 。

总时间复杂度最大为O(n⋅log2(min{a})) 。

实现
只有n ,sum 均为奇数时无法通过判断n 和sum 的奇偶性来得出答案。
计算出前缀gcdg1 和后缀gcdg2 ,然后计算gcd{g1[i−1],a[i]−1,g2[i+1]} ,如果 (sum−1)/gcd 为奇数就令所有数除以gcd,然后轮到对手。若没有可能的gcd,GG。

#include<cstdio>
#define N 110000
inline char gc(){
    static char now[1<<16],*T,*S;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
} 
inline int read(){
    int x=0;char ch=gc();
    while (ch<'0'||ch>'9') ch=gc();
    while (ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=gc();}
    return x;
}
inline int gcd(int x,int y){
    if (y==0) return x;return gcd(y,x%y);
}
int cur,n,a[N],mod,g1[N],g2[N];long long sum;
void printans(){
    if (!cur) printf("Second");else printf("First");
}
int main(){
    freopen("d.in","r",stdin);
    n=read();
    for (int i=1;i<=n;++i) a[i]=read(),(mod+=a[i]%2)%=2;
    if (n%2&&!mod) {printf("First");return 0;}
    if (!(n%2)) {if (mod) printf("First");else printf("Second");return 0;}
    while (1){sum=0;
        for (int i=1;i<=n;++i) g1[i]=gcd(a[i],g1[i-1]);
        for (int i=n;i>=1;--i) g2[i]=gcd(a[i],g2[i+1]);
        for (int i=1;i<=n;++i) sum+=a[i];int g;
        for (int i=1;i<=n;++i){
            if (a[i]==1) {printans();return 0;}
            g=gcd(g1[i-1],gcd(a[i]-1,g2[i+1]));
            if (((sum-1)/g)%2) break;
        }
        if (g==1) {printans();return 0;}
        for (int i=1;i<=n;++i) a[i]/=g;
        cur^=1;
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值