1. 程式人生 > >【博弈】AGC010D Decrementing

【博弈】AGC010D Decrementing

分析:

首先,有兩個很顯然的結論: 1、不考慮除以GCD的情況,就原問題而言(即只是-1),那麼勝負只跟偶數的個數有關:若有偶數個偶數,那麼後手必勝,反之先手必勝。 證明很簡單:很容易想到,奇數的位置其實是可以忽略的,因為當某個人從奇數位-1,另一個人一定可以再在那裡-1,又變為了奇數。偶數不能忽略,因為不一定偶數-1後還能再-1(可能就到1了,不能再-1)。所以每個偶數只需1次操作,就能變為奇數,既可以忽略。

換言之,這題就轉化為:有N個石子,每次可以拿走一顆,求誰勝誰負。這就顯然只跟石子的奇偶性有關了。

2、除以一個奇數,偶數的個數不變。

這證明就更簡單了:奇數/奇數=奇數,偶數/奇數=偶數。

所以,其實只有兩種情況: 1、直接根據偶數的個數分勝負。 2、嘗試所有數除以2

但是,除以2是沒那麼容易的: 如果A除以2後,A必敗,那A不可能去除以2。 如果A除以2後,B必敗,那麼B一定不會允許A除以2。

所以,除以2如果有效,那麼必須在B無法影響的情況下,A一步就達到除以2的條件了。 換言之,只有當前狀態有且僅有1個奇數(不為1)的情況下,並且除以2後能夠使得對方必敗。除以2才有效。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 100010 using namespace std; typedef long long ll; ll a[MAXN]; int n,now,cnt0,cnt1; ll gcd(ll x,ll y){ if(y==0) return x; return gcd(y,x%y); } bool solve(){ int cnt0=0,cnt1=0,now=0; for(int i=1;i<=n;i++){ if(a[i]%2ll==0) cnt0++; else{ cnt1++; now=i; } } if(cnt1==1&&
a[now]!=1){ ll g=0; a[now]--; for(int i=1;i<=n;i++) g=gcd(g,a[i]); for(int i=1;i<=n;i++) a[i]/=g; if(solve()==0) return 1; } if(cnt0%2==1) return 1; else return 0; } int main(){ //freopen("game.in","r",stdin); //freopen("game.out","w",stdout); SF("%d",&n); for(int i=1;i<=n;i++) SF("%lld",&a[i]); if(solve()) PF("First"); else PF("Second"); }