2348:Euclid's Game

keyword

互除法 Nim C++

概要

2つの数a,bがある。プレイヤーはaとbの大きい方から小さい数の何倍かを交互に引いていく。最初に数を0にした方が勝つ。最善を尽くしたとき先手と後手のどちらが勝つか求める問題。
ユークリッドの互除法でgcd(x,y)を呼んだときx/yの値を覚えておけばよい。こうすると一番左の山から1個以上石をとるようなルールのNimに落ちる。石が2個以上あるときは勝つのでこのNimは簡単に解ける。

vector<int> ns;
int gcd(int x, int y){
    if(y==0) return x;
    else{
        ns.PB(x/y);
        return gcd(y,x%y);
    }
}

int solve(int pos, int turn){
    if(pos==SZ(ns)-1) return turn;
    if(ns[pos]>1) return turn;
    else if(ns[pos]==1) return solve(pos+1, -turn);
    else if(ns[pos]==0) return solve(pos+1, turn);
    printf("error\n");
    return 0;
}

int main(){
    int n, m;
    while(scanf("%d%d",&n,&m)){
        if(!(n||m)) break;
        ns.clear();
        gcd(n,m);
        if(solve(0,1)==1) printf("Stan wins\n");
        else printf("Ollie wins\n");
    }
    return 0;
}