Codeforces Round #114 (Div. 1) C Wizards and Numbers

题目链接:Wizards and Numbers

题意:有两个数字a, b,假设 a>b,两个玩家进行游戏,有两种操作:1. 令 a=a-b^k,k为正数,且需要保证操作后 a 仍然非负;2. 令 a=a%b。最终有一个人无法操作(存在一个数为0)的时候便输了。

题解:如果只有操作2就是一个辗转相除法,实际上加上了操作1,执行的过程中也一定会出现辗转相除法种每轮的数字情况。所以以辗转相除法的每轮情况作为分段点,讨论其是必胜态还是必败态,首先(t, 0) 一定是必败态,所以其上一层的状态一定是必胜态。主要考虑当前层为必胜态,那上一层的情况为什么,问题实际上可以转化为有 tx 堆石子,每次可以 x的幕次颗,谁最先取光谁就输了。打个表找找规律便可以了:若 x 为奇数,则结果与 t 的奇偶有关;若 x 为偶数,则会在 x^2 处作为分界点,规律发生了变化,但还是很显然的。

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

LL xx[105],yy[105],cnt;

LL gcd(LL x,LL y){
    int res=(y==0?x:gcd(y,x%y));
    xx[++cnt]=x;
    yy[cnt]=y;
    return res;
}

LL ans[105];
bool check(LL a,LL b){
    if(a%2==1){
        return (b/a-1)%2;
    }
    else{
        if(a>=1000000000||b<a*a){
            return !((b/a)%2);
        }
        else{
            LL res=b/a;
            LL c1=(res%(a+1))%2;
            LL c2=res%(a+1);
            return !c1||(c2==a);
        }
    }
}
void solve(LL a,LL b){
    cnt=0;
    gcd(a,b);
    ans[1]=0;
    for(int i=2;i<=cnt;i++){
        if(ans[i-1]==0) ans[i]=1;
        else if(check(yy[i],xx[i]-yy[i-1])) ans[i]=1;
        else ans[i]=0;
    }
    if(ans[cnt]) printf("First\n");
    else printf("Second\n");
}

int p=12;
int biao[100005];
int dabiao(int x){
    if(biao[x]!=-1) return biao[x];
    if(x<0) return 0;
    int temp=p;
    int flag=0;
    while(temp<=x*p){
        if(dabiao(x-temp/p)==0){
            flag=1; break;
        }
        temp*=p;
    }
    return biao[x]=flag;
}

int main(){
    /*******
    memset(biao,-1,sizeof(biao));
    biao[0]=1;
    dabiao(100);
    for(int i=1;i<=100;i++){
        cout<<i<<" "<<biao[i]<<endl;
    }
    *******/
    int n;
    cin>>n;
    while(n--){
        LL a,b;
        cin>>a>>b;
        if(a<b) swap(a,b);
        if(b==0) cout<<"Second"<<endl;
        else if(a%b==0) cout<<"First"<<endl;
        else solve(a,b);
    }

    return 0;
}

 

posted on 2019-01-17 13:12  Psong  阅读(149)  评论(0编辑  收藏  举报

导航