P1290 欧几里德的游戏

传送门

肯定是博弈论啦

因为大家都"完美地操作"

所以结果是肯定的

那考虑怎样先手才能控制必胜局面

设大的数是 a,另一个数是b

如果把数变成 b,a%b的局面必胜

那先手肯定走这一步,先手必胜

如果b,a%b的局面必输

那先手就要尽量避免,而且要尽量让后手变成  不得不取成b,a%b的必输局面

考虑怎样才有 不得不 取成b,a%b的必输局面

显然如果  a < 2 * b

就只能 变成 b,a-b,即 b,a%b

如果先手时的 a >=2 * b

那么先手只要把 a 减到 a%b+b 就能保证必胜(显然只要减若干个 b ,a 就可以变成 a%b+b)

如果先手面对的是 a< 2 * b的局面...

那就只能减了...

那此时就成了 b , a%b的局面,而且是后手的回合了..

相当于现在后手成了先手,面对 b,a%b 的局面

然后继续判断下去就好了

复杂度log(a)...

讲一下复杂度的证明吧,不想听也可以跳过...


 

如果 a >= 2*b,那就结束了

否则 a < 2*b 所以 a/2 < b  

那减完一次,显然只能减一个b,不然就变成了负数了

因为 a/2 < b,a/2 = a - a/2

所以 a - b < a - a/2 = a/2

即  每次减后 a 至少除以 2

所以最多只要log( a ) 次就能得出结果....


 

注意一下刚开始 a=b 的情况特判一下

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
long long n,m;
int num;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        num=0;
        cin>>n>>m;
        if(n<m) swap(n,m);
        if(n==m)
        { 
            cout<<"Stan wins"<<endl;
            continue;
        }
        while(n<2*m)//如果n>=2*m,那么结果就确定了
        {
            num++;
            n-=m;
            swap(n,m);
        }
        if(!(num&1)) cout<<"Stan wins"<<endl; //如果num为偶数,即当为 Stan 的回合时能保证比胜
        else cout<<"Ollie wins"<<endl; //否则就是 Ollie 必胜
    }
    return 0;
}

 

posted @ 2018-08-29 15:11  LLTYYC  阅读(144)  评论(0编辑  收藏  举报