题意
有两堆石子,数量分别为(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)的必败态分布情况为
观察这个分布,得到一个规律:
((a,b))的(b-a)值以(2,4,6,8,10,12,14,16,18,20,dots)递增
这可能是一个入手点,那么我们把(k=0)的表打出来试试
当(k=0)时,最小数据必败态为((1,2))
按规律打表如下
得到(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)时,必败态为
当(k=3)时,必败态为
当(k=4)时,必败态为
于是我们得到了五个数列({b}),如下
根据OEIS的输出,得出(需要稍微转化一下)
容易发现规律,并得到通项表达如下
((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)
(但我不会,还没学)
所以想学的可以去别的地方学学
最后如果以通项方式解决,通项应该也是上面推出的那个
据说还有更简单的递推方法
我直接问号为敬?????
最后这里放一下同校另外两位大佬本题的博客