0423 连续扔骰子
* * * *
拉格朗日计划
* * * *
连续扔骰子

连扔一个六面骰子n次,记c是其中连续两次掷出同样点数的次数。

例如若$n=7$,掷出的点数分别是1,1,5,6,6,6,3,则$c=3$(一次1,1,两次6,6)。

记C(n)为连扔一个六面骰子n次且连续两次掷出同样点数的次数c不超过$\pi(n)$的结果总数,其中$\pi(n)$表示不超过n的素数总数。

可以验证$C(3)=216, C(4)=1290, C(11)=361912500, C(24)=4727547363281250000$。

再记$S(L)=\sum_{n=1}^LC(n)$。可以验证$S(50) \bmod (10^9+7)=832833871$。

求$S(5\times 10^7) \bmod (10^9+7)$。

本题难度:



解答

n次中有c个连续同样点数的扔法总数是 $$P(n,c)=\binom{n-1}{c}\cdot5^{n-c-1}\cdot6,$$ 这是因为需要在$n-1$个位置中选出c个作为出现连续同样点数的位置,每个连续同样点数都有6种可能,而其他位置的点数因为要与前一个位置相异所以只有5种可能。从而 $$C(n)=\sum_{c=0}^{\pi(n)}\binom{n-1}{c}\cdot5^{n-c-1}\cdot6=\begin{cases}6C(n-1)+5B(n-1,\pi(n)) & n\text{为素数} \\ 6C(n-1)-B(n-1,\pi(n)) & n\text{为合数} \end{cases}.$$ 递推计算即得结果$653972374$。

注:因组合数模余的计算中需要使用sympy求乘法逆,以下代码为Python 3,其中还打印了进度信息。

import sympy,math

target=50000000
mod=10**9+7
tick=target//100

P=[1-i%2 for i in range(target-2)]
for i in range(3,math.isqrt(target+1)+1,2):
    if P[i-3]:
        for j in range(2*i-3,len(P),i):
            P[j]=0

print("initialization completed, start checking...")

d,c,s,x=1,36,42,6
for n,p in enumerate(P,start=3):
    c=(c*6-x)%mod
    if p:
        d+=1
        x=(x*(n-1)*sympy.mod_inverse(d,mod))%mod
        c=(c+x)%mod
    else:
        x=(x*(n-1)*sympy.mod_inverse(n-1-d,mod)*5)%mod
    s=(s+c)%mod
    if n%tick==0:
        print(n//tick,"percent completed, current sum:",s)
print(s)