首先考虑最简单的情况,如果有一个数是 \(1\),那么第二步没有作用,胜负是固定的,先判掉。
然后发现题目给了一个很奇怪的条件:所有数的最大公约数为 \(1\),也就是至少有一个奇数,这提示我们从奇偶数下手。
发现第二步中的最大公约数的奇数因子是毫无意义的,因为无论是奇数还是偶数除以一个奇数,奇偶性都不变,没有改变第一步操作次数的奇偶性。
这给了先手一种必胜的思路,如果只进行第一步,先手必胜,先手又能保证两人每一次第二步中的最大公约数为奇数就必胜。
先手只需要每一次随便选一个偶数减 \(1\),由于初始至少有一个奇数,所以后手操作的时候至少有两个奇数,最大公约数一定为奇数,先手的操作最大公约数就更显然是奇数了。
这种情况的初始条件是只进行第一步先手必胜,也就是偶数个数为奇数。
如果只进行第一步先手必败呢?这时候先手肯定不能留给后手奇数,否则后手采用前面的方法必胜。所以先手只有一种选择,第一步删奇数。
如果初始奇数的个数大于 \(1\),那么先手删不完所有的奇数,后手必胜。
到现在,我们有三种判定了:
- 如果有 \(1\) 直接判定
- 如果有奇数个偶数先手必胜
- 如果有偶数个偶数并且有大于一个奇数后手必胜
如果恰好有偶数个偶数而且只有一个奇数,先手会删那个奇数,直接模拟这一次操作将奇数减 \(1\),这时所有的数都为偶数,最小公因数最小为 \(2\),最多进行 \(log\) 次就会变成上面三种情况的一种。
单次模拟时间复杂度为 \(O(nloga)\),总时间复杂度为 \(O(nlog^{2}a)\)。
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n;
int a[N];
int ji,ou,now=1,sum=0;
bool flag=false;
void change(){
for(int i=1;i<=n;i++){
if(a[i]&1) a[i]--;
}
int gcd=a[1];
for(int i=2;i<=n;i++) gcd=__gcd(gcd,a[i]);
for(int i=1;i<=n;i++) a[i]/=gcd;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]&1) ji++;
else ou++;
if(a[i]==1) flag=true;
sum+=(a[i]-1);
}
if(flag){
if(sum&1) cout<<"First";
else cout<<"Second";
return 0;
}
if(ou&1){
cout<<"First";
return 0;
}
else if(!(ou&1) && ji>1){
cout<<"Second";
return 0;
}
while(1){
now=3-now;
change();
ji=ou=0;
sum=0;
for(int i=1;i<=n;i++){
if(a[i]&1) ji++;
else ou++;
if(a[i]==1) flag=true;
sum+=(a[i]-1);
}
if(flag){
if(!(sum&1)) now=3-now;
break;
}
if(ou&1){
break;
}
else if(!(ou&1) && ji>1){
now=3-now;
break;
}
}
if(now==1) cout<<"First";
else cout<<"Second";
return 0;
}
标签:先手,AGC010D,必胜,int,奇数,偶数,Decrementing,最大公约数
From: https://www.cnblogs.com/wangwenhan/p/18489109