zoukankan      html  css  js  c++  java
  • 【hdu 1527】取石子游戏

    Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 6706 Accepted Submission(s): 3646

    Problem Description
    有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。

    Input
    输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,000。

    Output
    输出对应也有若干行,每行包含一个数字1或0,如果最后你是胜者,则为1,反之,则为0。

    Sample Input
    2 1
    8 4
    4 7

    Sample Output
    0
    1
    0

    【题目链接】:http://acm.hdu.edu.cn/showproblem.php?pid=1527

    【题解】

    /*
        假设剩余的石子为(i,j);(不妨设i<=j)
        有这样的必败点
        (0,0) (1,2) (3,5) (4,7) (6,10)...
        设为(n,m)为第x对必败点;(从0开始);
        这里的n是前面的x-1对必败点中没有出现的最小整数;
        m则等于n+x
        这里的n有通项公式n=[x*(1+√5)/2]
        [x]为不超过x的最大整数;
        ①证所有的自然数都有出现在必败点中;
            n[x]是之前没有出现过的自然数;所以n[x]>n[x-1];
            又m[x]=n[x]+x>n[x-1]+x-1=m[x-1]>n[x-1]
            所以m[x]比之前出现过的所有数字都大;即也没有出现过;
            又n[x]是之前没有出现过的数中最小的那个;
            则可知所有的自然数都出现在了必败点中;(可能在i也可能在j);
        ②证所有的必败点都能在规则允许的操作内推出必胜点;
            (i,j)->(i+t,j)||(i,j+t)||(i+t,j+t);
            显然都是合法的操作;t取任意实数都能推出一个必胜点;
            (且因为它们两个的差是固定的k,则不可能是下一个必败点);
        ③证所有的不是上述必败点的都是必胜点(能转移到必败点);
            设非必败点为(i,j)这里i<=j
            因为所有的自然数都在必败点当中(是必败点对中的一个)
            则
            一.若i=n[x],
                1' j>m[x]
                    则可以让j减少j-m[x]就变成必败点了;
                2' j<m[x]
                    则可以让(n[x],j)->(n[j-n[x]],n[j-n[x]]+j-n[x])
                    即i和j同时减少n[x]-n[j-n[x]]
                    这里因为j>=i,所以j>=n[x];
                    而变化后的点是一个合法的必败点;
            二.若j=m[x]
                1' i>n[x]
                    则让i减少i-n[x],这样(i,j)就变成必败点了;
                2' i<n[x]
                    这里还有分类
                    i肯定是某个必败点的元素;(自然数都是必败点的元素);
                        ①如果i=n[x0](x0<x)
                         则j=m[x]>m[x0];
                         则让j减去j-m[x0]就又得到一个必败点了;
                         ->(n[x0],m[x0])
                        ②如果i=m[x0](x0<x)
                         j=m[x]>m[x0]>n[x0];
                         则让j减去j-n[x0];
                         这样i会变成大于j的了
                         ->(m[x0],n[x0]);
                         但是没关系再倒回了就好;
                         总之又得到了必败点
            综上不是必败点就一定是必胜点(所以证明②有什么用?:))
        则对于输入,
        先保证a<b
        然后x=b-a
        看看x*(1+√5)/2是不是等于a;
        如果是,则为必败点;
        否则为必胜点;
    */

    【完整代码】

    #include <bits/stdc++.h>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define LL long long
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define rei(x) scanf("%d",&x)
    #define rel(x) scanf("%I64d",&x)
    
    typedef pair<int,int> pii;
    typedef pair<LL,LL> pll;
    
    //const int MAXN = x;
    const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};
    const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};
    const double pi = acos(-1.0);
    
    int a,b;
    
    int main()
    {
        //freopen("F:\rush.txt","r",stdin);
        while (~scanf("%d%d",&a,&b))
        {
            if (a>b)
                swap(a,b);
            int x = b-a;
            int temp = floor(x*(1.0+sqrt(5))/2.0);
            if (temp==a)
                puts("0");
            else
                puts("1");
        }
        return 0;
    }
    
  • 相关阅读:
    生信入门-爱课程上的华中农业大学
    PAT 1115 Counting Nodes in a BST[构建BST]
    PAT 1133 Splitting A Linked List[链表][简单]
    PAT 1037 Magic Coupon[dp]
    PAT 1033 To Fill or Not to Fill[dp]
    畅通工程续 HDU1874
    Free DIY Tour HDU1224
    六度分离 HDU1869
    Arbitrage HDU1217
    floyed算法
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626728.html
Copyright © 2011-2022 走看看