Examples

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;
}
posted @ 2022-09-09 16:58  xiaoziyao  阅读(57)  评论(1编辑  收藏  举报