• 2020杭电多校 9C / HDU 6869


    HDU 6869 - Slime and Stones


    题意

    有两堆石子,数量分别为(a,b),两人轮流取,每次必须取一个及以上的石子

    每次可以任选一堆取(个数不限),也可以两堆都取(取的个数差值必须(leq k)

    两人都以最优策略取石子,问是否存在一种情况使得先手必胜,是则输出(1),否则输出(0)


    限制

    (1leq Tleq 10^5)

    (1leq a,bleq 10^8, 0leq kleq 10^8)




    赛时思路

    这部分解法可能是现场赛几乎不可能实现的写法吧

    • 下文令((x,y))表示现在两堆石子的数量,限制(xleq y)

    首先考虑最小数据的必败态

    根据题意可以得知,谁将某一堆石子取完,那么他的对手就可以取完另外一堆,所以这种方式必败

    或者如果两堆石子数量差在(k)之内((|a-b|leq k)),那么就可以直接拿走两堆内所有石子并获胜

    所以可以得到,如果较少的堆内剩余(1)粒石子,较多的堆内剩余(k+2)粒,那么当前不论怎么操作都会输掉这场比赛

    得到:((1,k+2))为最小数据下的必败态

    为了找到规律,我们枚举两堆石子中较少堆的数量


    当较少的堆中仅存在(1)粒石子时——

    当剩余情况为((1,i), 1leq ileq k+1)时,当前操作的人可以直接拿完两堆,所以必胜

    当剩余情况为((1,k+2))时,必败

    当剩余情况为((1,i), igeq k+3)时,当前操作的人可以将其转换到((1,k+2))的情况,所以必胜


    相同的,当较少的堆中仅存在(2)粒石子时——(这里不适用于(k=0)的情况)

    当剩余情况为((2,i), 2leq ileq k+2)时,当前操作的人可以直接拿完两堆,所以必胜

    当剩余情况为((2,i), k+3leq ileq 2k+3),将较少的堆拿去(1)粒,较大的堆最多可以拿(k+1)粒,所以可以转移到((1,k+2))的状态,所以必胜

    当剩余情况为((2,2k+4))时,必败

    当剩余情况为((2,i), igeq 2k+5)时,当前操作的人可以将其转换到((2,2k+4))的情况,所以必胜


    直到较少的堆内存在(k+2)粒石子时,情况发生了变化——

    当剩余情况为((k+2,i), k+2leq ileq 2k+3)时,当前操作的人可以直接拿完两堆,必胜

    当剩余情况为((k+2,i), igeq 2k+4)时,发现前面有个必败态((1,k+2)),他们共享(k+2)这个状态,所以可以从((k+2,2k+4))直接转换到((1,k+2))的状态,所以该情况下必胜


    综上,可以得到的一个规律就是

    后面的一个必败态总是可以由前一个必败态推导而来

    假设((x,y))是一个必败态,假设较小的堆被拿了(1)粒石子,那么较大的堆最多能拿(k+1)粒石子

    显然,((x+1,y+k+2))无法仅通过一步就推到((x,y)),可能必败

    还要考虑一点,就是(x+1)没有在前面的任意必败态中出现过,否则可以直接一步转移到更前面的必败态,使得该点必胜

    如果(x+1)并未出现在前面任意一个必败态中,就可以肯定((x+1,y+k+2))无法转移到任意一个必败态,则它不是必胜态,是一个必败态


    (k=1)的情况为例,最小必败态为((1,3))

    考虑((x+1,y+k+2))的转移方式,显然(x+1=2)并未出现在前面任意一个必败态中

    所以((2,6))是一个必败态

    继续考虑,发现下一个状态为((3,9))

    但是(3)存在于必败态((1,3))内,说明((3,9))可以直接转换到((1.3)),这是个必胜态

    为了让其不能一遍转移得到,则可以假设两堆都多取了一粒石子,即考虑((x+1+1,y+k+2+1))

    发现(2+1+1=4)并未出现,所以((4,10))是一个必败态

    一直这样考虑下去,粗略得到(k=1)的必败态分布情况为

    [(1,3)\(2,6)\(4,10)\(5,13)\(7,17)\ (8,20)\(9,23)\(11,27)\(12,30)\(14,34)\ (15,37)\(16,40)\(18,44)\(19,47)\(21,51)\ (22,54)\(24,58)\(25,61)\(26,64) ]

    观察这个分布,得到一个规律:

    ((a,b))(b-a)值以(2,4,6,8,10,12,14,16,18,20,dots)递增

    这可能是一个入手点,那么我们把(k=0)的表打出来试试


    (k=0)时,最小数据必败态为((1,2))

    按规律打表如下

    [(1,2)\(3,5)\(4,7)\(6,10)\(8,13)\ (9,15)\(11,18)\(12,20)\(14,23)\(16,26)\ (17,28)\(19,31)\(21,34)\(22,36)\(24,39)\ (25,41)\(27,44) ]

    得到(b-a)的值以(1,2,3,4,5,6,7,dots)递增


    可以得到,(b-a)的值是一个首项为(k+1),公差为(k+1)的等差数列

    所以我们可以根据(frac {b-a}{k+1})来确定某个状态在必败态中的项数

    如果你想问为什么要求出项数,看下面……


    实际上打出表就能发现

    必败态的(b)数值分布存在一个规律((b_i-b_{i-1}in{k+2,k+3})

    假如这个({b})数列存在着通项公式,那么肯定是形如(b_i=lfloor i imes k floor, kinR)

    这样才能保证前后两项差值固定在一个集合内(虽然这个常数(k)可能很难表示)

    那么我们就大胆着手于找通项公式

    这里开始往下应该也可以采用线性递推模板解决,不过我没试过,不确定会不会被卡

    打开OEIS,准备尝试玄学求出可能的通项(这是个能根据数列前几项或者中间几项求出通项公式的工具)

    但不同的(k)肯定对应着不同的通项公式,所以我们再把(k=2,3,4)的表稍微打出前几项


    (k=2)时,必败态为

    [(1,4)\(2,8)\(3,12)\(5,17)\(6,21)\ (7,25)\(9,30)\(10,34)\(11,38)\(13,43)\ (14,47)\(15,51)\(16,55) ]

    (k=3)时,必败态为

    [(1,5)\(2,10)\(3,15)\(4,20)\(6,26)\ (7,31)\(8,36)\(9,41)\(11,47)\(12,52)\ (13,57)\(14,62) ]

    (k=4)时,必败态为

    [(1,6)\(2,12)\(3,18)\(4,24)\(5,30)\ (7,37)\(8,43)\(9,49)\(10,55)\(11,61)\ (13,68)\(14,74)\(15,80) ]


    于是我们得到了五个数列({b}),如下

    [{b}= left { egin{aligned} 2,5,7,10,13,15,18,20,&23,26,28,31,34,dots (k=0)\ 3,6,10,13,17,20,23,27,&30,34,37,40,44,dots (k=1)\ 4,8,12,17,21,25,30,34,&38,43,47,51,55,dots (k=2)\ 5,10,15,20,26,31,36,&41,47,52,57,62,dots (k=3)\ 6,12,18,24,30,37,43,&49,55,61,68,74,dots (k=4)\ dots & end{aligned} ight . ]

    根据OEIS的输出,得出(需要稍微转化一下)

    [b_n= left { egin{aligned} lfloor n imes frac{3+sqrt 5}{2} floor&, k=0\ lfloor n imes frac{4+sqrt 8}{2} floor&, k=1\ lfloor n imes frac{5+sqrt {13}}{2} floor&, k=2\ lfloor n imes frac{6+sqrt {20}}{2} floor&, k=3\ lfloor n imes frac{7+sqrt {29}}{2} floor&, k=4\ dots & end{aligned} ight . ]

    容易发现规律,并得到通项表达如下

    [b_k=lfloor n imes frac{x+sqrt y}{2} floor\ x=k+3\ y=5+frac{3+(k imes 2+1)}{2} imes k ]

    (y)({5,8,13,20,29,dots}),每项差(3,5,7,9,dots),可以拆成(5+)等差数列求和)


    得到了({b})数列的通项,那该怎么判断对应的是哪一项,是不是必败态呢

    前面提到,我们能够根据(b-a)的值获得项数为(frac{b-a}{k+1})

    根据项数代入公式即可求出必败态这一项的(b)

    判断下两个(b)是不是相同的就能确定是不是必败态了



    程序

    (78ms/1000ms)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    void solve()
    {
        ll a,b,k;
        scanf("%lld%lld%lld",&a,&b,&k);
        if(a>b)
            swap(a,b);
        if((b-a)%(k+1)==0)
        {
            int id=(b-a)/(k+1);
            ll x=3+k,y=(3+k*2+1)*k/2+5;
            ll tmp=(x+sqrt(y))*id/2.0;
            if(tmp==b)
                puts("0");
            else
                puts("1");
        }
        else
            puts("1");
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
            solve();
        return 0;
    }
    /*
    10
    15 37 1
    26 64 1
    21 51 1
    9 23 1
    25 41 0
    27 44 0
    14 62 3
    20 105 4
    19 99 4
    8 36 3
    */
    



    原版博弈

    本题是威佐夫博弈(Wythoff's game)的变种

    原版威佐夫博弈正是本题(k=0)时的情况

    结论是:

    假设两堆石子数量为((x,y), xlt y)

    先手必败,当且仅当满足(frac{sqrt 5+1}{2}(y-x)=x)

    (但我不会,还没学)

    所以想学的可以去别的地方学学

    最后如果以通项方式解决,通项应该也是上面推出的那个




    据说还有更简单的递推方法

    我直接问号为敬?????

    pic




    最后这里放一下同校另外两位大佬本题的博客

    禾硕。

    溢流眼泪


  • 相关阅读:
    第六周 组合数据类型
    第五周 函数和代码复用
    第四周 程序的控制结构
    第三周 Python基本数据类型
    python库
    sublime text3自定义设置及快捷键大全
    Sublime Text3插件安装教程
    Linux 标准目录结构
    快学Scala-10--List 和Set
    快学Scala-09--模式匹配
  • 原文地址:https://www.cnblogs.com/stelayuri/p/13525300.html
Copyright © 2020-2023  润新知