• 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;
    }
  • 相关阅读:
    noip模拟赛 双色球
    noip模拟赛 czy的后宫
    noip模拟赛 经营与开发
    bzoj1297 [SCOI2009]迷路
    Android(java)学习笔记140:常用的对话框
    Java基础知识强化02:import static 和 import
    Java基础知识强化01:short s = 1; s = s + 1;与short s = 1; s += 1;
    GUI编程笔记(java)11:使用Netbeans工具进行GUI编程
    GUI编程笔记(java)10:GUI实现一级菜单
    GUI编程笔记(java)09:GUI控制文本框只能输入数字字符案例
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9554449.html
Copyright © 2020-2023  润新知