题解:P15985 [PA 2026] 骰子 / Kostki

· · 题解

这个过程有不可避免的指数状态量,因此考虑先拆贡献,答案是每个玩家在每个数值进行操作的概率之和。

拆贡献首先需要考虑计算某个固定局面出现的概率。

不难发现每个玩家掷骰子的数值独立,即每个玩家第 1,2,\dots 次骰出的值独立。因此,考虑预先确定每个玩家的骰子序列,在骰子序列固定的情况下,一个局面的出现概率是 01。因此我们只需要记录合法的骰子序列个数。

那么枚举最小值 i,计算玩家经过 i 的概率 f_i 和玩家跳过 i 且没有跨过 m 的概率 g_i,求 f,g 是简单的。

i 一步跨过 m 的概率为 p_i,枚举 i 产生的贡献次数,后面就是朴素的推式子了,答案为:

\sum_i \sum_{x=1}^{n} \sum_{j=1}^{x} (1-p_i)^{j} \binom{n}{x} f_{i}^x g_{i}^{n-x} \\ =\sum_i \sum_{x=1}^{n} \binom{n}{x} f_{i}^x g_{i}^{n-x} \frac{1-(1-p_i)^x}{p_i} \\ =\sum_i \frac{1}{p_i}\sum_{x=1}^{n} \binom{n}{x} f_{i}^x g_{i}^{n-x} (1-(1-p_i)^x) \\ =\sum_i \frac{1}{p_i}((f_i+g_i)^n-(g_i+(1-p_i)f_i)^n)

注意特判 p_i=0 的情况,推导过程与上述类似。

```cpp #include<bits/stdc++.h> using namespace std; #define ll long long const ll mod=1e9+7; ll ksm(ll a,ll b){ ll res=1; while(b){ if(b&1) res=res*a%mod; a=a*a%mod; b/=2; } return res; } int n,k,m; ll f[1000005],g[1000005]; ll sumf[1000005],sumfx[1000005]; ll getf(int l,int r){ if(l>r||r<0) return 0; r=min(r,m); ll res=sumf[r]; if(l>0) res-=sumf[l-1]; res=(res+mod)%mod; return res; } ll getfx(int l,int r){ if(l>r||r<0) return 0; r=min(r,m); ll res=sumfx[r]; if(l>0) res-=sumfx[l-1]; res=(res+mod)%mod; return res; } int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>k>>m; f[0]=sumf[0]=1; ll invk=ksm(k,mod-2); for(int i=1;i<=m;i++){ f[i]=getf(i-k,i-1)*invk%mod; sumf[i]=(sumf[i-1]+f[i])%mod; sumfx[i]=(sumfx[i-1]+f[i]*i%mod)%mod; } for(int i=1;i<m;i++){ //j<i //j+k>i,j>i-k //j+k<m,j<m-k [m-k,i-1] if(i-1+k<m){ g[i]=getf(i+1-k,i-1)*(k-i)%mod*invk%mod; g[i]=(g[i]+getfx(i+1-k,i-1)*invk%mod)%mod; }else{ g[i]=getf(i+1-k,m-k-1)*(k-i)%mod*invk%mod; g[i]=(g[i]+getfx(i+1-k,m-k-1)*invk%mod)%mod; g[i]=(g[i]+getf(m-k,i-1)*(m-i-1)%mod*invk%mod)%mod; } } ll ans=0; for(int i=0;i<m;i++){ //i+x>=m,x>=m-i,k-(m-i)+1 int t=k-(m-i)+1; ll p=0; if(t<=0) p=0; else p=t*invk%mod; if(p){ ll res=ksm((f[i]+g[i])%mod,n)-ksm((g[i]+(1-p+mod)*f[i])%mod,n); ans=(ans+res*ksm(p,mod-2)%mod+mod)%mod; }else{ ans=(ans+f[i]*n%mod*ksm((f[i]+g[i])%mod,n-1))%mod; } } cout<<ans<<"\n"; return 0; } ```