0344 银币游戏
* * * *
拉格朗日计划
* * * *
银币游戏

银币游戏是荷兰数学家de Bruijn提出的一类问题,它的一种形式如下:

在一条长度有限纸带上放有一些硬币,这些硬币中只有一枚银币是有价值的。纸带由大小相同的方格组成,每个方格内最多可放一枚硬币。

两名玩家轮流操作,每一轮玩家可以选择进行一次常规操作或者进行一次特殊操作。

常规操作就是选择一枚硬币,并将其向左移动若干格(至少一格),但移动时不能跳过其它硬币,也不能移出纸带。

特殊操作即将最左侧的硬币放进自己的口袋。无法执行常规的操作必须执行特殊操作,最终获得银币的玩家获胜。



先手必胜的硬币放置状态称为必胜态。记$W(n,c)$为有n个方格和c枚无价值硬币时的必胜态的数量。

可以验证$W(10,2)=324$以及$W(100,10)=1514704946113500$。

求$W(1000000,100)$模半素数$1000036000099(=1000003\times1000033)$的余数。

本题难度:



解答

本题与第301题第306题第310题第325题的背景都相同,即NIM游戏的变体,本题也是第二道官网难度标记为100\%的问题,以下仅作扼要提示:

用$x_1,\ldots,x_{101}$来表示这些硬币的位置。若银币在最左侧,则显然先手直接胜,否则若$x_k$是硬币,则再记$x_0=2-k$。

令$y_i=x_{2i+i}-x_{2i}-1$,则本游戏就转换为了每堆数量为$y_i$的取石头游戏(即NIM),从而只有在全部$y_i$的异或值为$0$时后手胜。

注意后手总是可以保持异或值不变,这是因为若某个$y_i$增加,说明$x_{2i}$被左移,则只需将$x_{2i+1}$移动同样的距离。

若其减少但未减至0,则后手可以将其减少至0来保持异或值。若其减少至0,则后手可以将另一项$y_{i'}$减少至0,同样可以保持异或值。

而$x_0$的选取刻画了胜负条件,例如$x_2$是银币时任意一方都不会将$y_0$减少到0,否则下一轮对手直接获胜。

用动态规划递推汇总$y_i$之和为t,且异或值为$0$的局面数,最终结果是$65579304332$。

注:因需要用到math.comb方法,以下代码为Python 3。

import math

def f(k,shift=0):
    r=0
    m=n-c
    d=[0]*(m+1)
    d[0]=1
    for t,x in enumerate(d):
        if x>0:
            r+=x*math.comb(m-(t+shift)+p,p)
            for i in range(2*(t==0),min([m-2*t,p+k])+1,2):
                d[2*t+i]+=x*b[k][i]
    return r

n=10**6
c=100 
p=50
b=[[math.comb(p+i,j) for j in range(p+i+1)] for i in range(2)]

print(((c+1)*math.comb(n,c+1)+(c-1)*(f(0)-f(1))-f(1,1))%1000036000099)