2020杭电多校 9C / HDU 6869 - Slime and Stones (线性递推/威佐夫博弈)

HDU 6869 - Slime and Stones


题意

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

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

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


限制

\(1\leq T\leq 10^5\)

\(1\leq a,b\leq 10^8,\ 0\leq k\leq 10^8\)




赛时思路

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

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

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

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

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

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

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

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


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

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

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

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


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

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

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

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

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


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

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

当剩余情况为\((k+2,i),\ i\geq 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\times k\rfloor,\ k\in\R\)

这样才能保证前后两项差值固定在一个集合内(虽然这个常数\(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 \{ \begin{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} \right . \]

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

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

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

\[b_k=\lfloor n\times \frac{x+\sqrt y}{2} \rfloor\\ x=k+3\\ y=5+\frac{3+(k\times 2+1)}{2}\times 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;
}



原版博弈

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

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

结论是:

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

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

(但我不会,还没学)

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

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




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

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

pic




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

禾硕。

溢流眼泪


posted @ 2020-08-18 19:03  StelaYuri  阅读(439)  评论(3编辑  收藏  举报