xsy1922B 序列 解题报告
题意
见 AC-Evil 序列合并。(下文也借鉴了这篇题解)
分析
首先最大值肯定不会超过 \(n+m-1\),令 \(t\leftarrow \min(t,n+m-1)\)。
我们将“序列长度为 \(i\) 时,序列的第一个数最后是 \(j\)”这一事件分解成两个事件:
- “序列长度为 \(i\) 时,序列的第一个数变成了 \(j\)”(称其为 A 事件);
- “序列长度为 \(i\) 时,序列的第一个数在变成 \(j\) 后没有变化了”(称其为 B 事件)。
于是设出 dp 状态,A 事件的概率,以及 A 事件发生时答案的条件期望,\(u_{i,j},v_{i,j}\),B 事件的概率,以及 B 事件发生时答案的条件期望 \(f_{i,j},g_{i,j}\)。
很容易写出 \(u_{i,j},f_{i,j},v_{i,j}\) 的转移方程:
\[u_{i,j}=\frac{[j\leqslant m]}{m}+u_{i,j-1}u_{i-1,j-1}\\
f_{i,j}=1-[j<t]u_{i-1,j}\\
v_{i,j}=f_{i,j}g_{i,j}+(1-f_{i,j})v_{i,j+1}
\]
(就是讨论一下会不会合并)
\(g_{i,j}\) 的转移稍微复杂一点:(令 \(P(E)\) 为 E 事件发生的概率)
下文中的序列为“除去第一个数字后的序列”,并称原序列的第一个元素为 \(w\)。
\[g_{i,j}=j+\sum_SS\times P(序列之和为\ S\mid B\ 事件)\\
=j+\sum_S\frac{S\times P(序列之和为\ S,w\ 不改变\mid w=j)}{P(w\ 不改变\mid w=j)}\\
=j+\sum_S\frac{(\sum_{k=1}^t u_{i-1,k}f_{i-1,k}g_{i-1,k})-[j<t]u_{i-1,j}v_{i-1,j}}{f_{i,j}}
\]
为了避免逆元,我们只需令 \(g_{i,j}\leftarrow f_{i,j}g_{i,j}\) 即可。
复杂度 \(O(n(n+m))\)。
代码
#include<stdio.h>
#include<iostream>
using namespace std;
const int maxn=2005,mod=1000000007;
int n,m,t,ans,ivm;
int u[maxn][maxn],v[maxn][maxn],f[maxn][maxn],g[maxn][maxn];
int ksm(int a,int b){
int res=1;
while(b){
if(b&1)
res=1ll*res*a%mod;
a=1ll*a*a%mod,b>>=1;
}
return res;
}
int main(){
scanf("%d%d%d",&n,&m,&t),t=min(t,n+m-1),ivm=ksm(m,mod-2);
for(int i=1;i<=n;i++){
int sum=0;
for(int j=1;j<=t;j++)
sum=(sum+1ll*u[i-1][j]*g[i-1][j])%mod;
for(int j=1;j<=t;j++){
u[i][j]=((j<=m? ivm:0)+1ll*u[i][j-1]*u[i-1][j-1])%mod;
f[i][j]=(1-(j<t? u[i-1][j]:0)+mod)%mod;
g[i][j]=(1ll*f[i][j]*j+sum-(j<t? (1ll*u[i-1][j]*v[i-1][j]%mod):0)+mod)%mod;
}
for(int j=t;j>=1;j--)
v[i][j]=(g[i][j]+1ll*(1-f[i][j]+mod)*v[i][j+1])%mod;
}
for(int i=1;i<=t;i++)
ans=(ans+1ll*u[n][i]*g[n][i])%mod;
printf("%d\n",ans);
return 0;
}