CF708E题解

考虑 f(n,x,y) 表示第 n 行左边被删了 x 个右边被删了 y 个的概率。

考虑用所有方案减去不连通的,g(x,y) 表示某行左边被删 x 个右边被删 y 个的的概率,S(n)=x+y<mf(n,x,y)有:

f(n,x,y)=g(x,y)(S(n1)YmxXmyf(n1,X,Y))

容易发现 g 的定义中左边和右边没有任何关系,所以可以写成 g(x,y)=P(x)P(y),稍微写写有:

P(n)=(kn)pn(1p)kn

容易发现 f 的转移具有对称性,这样会导致 f(n,x,y)=f(n,y,x)。(g 也一样)

F(n,k)=xkf(n,x,y)

可以重写转移:

f(n,x,y)=P(x)P(y)(S(n1)F(n1,mx)F(n1,my))

考虑对 F 进行转移而不是 f

容易发现 S(n) 相当于 F(n,0)

重新设 F(n,k)=y=kf(n1,x,y),这样就只需要最后处理一个后缀和即可。

F(n,x)=y=0mx1P(x)P(y)(S(n1)F(n1,mx)F(n1,my))=P(x)(S(n1)F(n1,mx))y=0mx1P(y)P(x)y=0mx1P(y)F(n1,my)

随便前缀和优化一下即可,复杂度 O(nm)

初始值 F(0,0,0)=1,答案为 S(n)

题外话,这题不值 *3100 吧。

#include<cstdio>
namespace SOLVE{
	const int M=1505,mod=1e9+7;
	int n,m,k,p,P[M],F[M],G[M],S1[M],S2[M];
	inline int pow(int a,int b=mod-2){
		int ans(1);for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)ans=1ll*ans*a%mod;return ans;
	}
	inline void main(){
		scanf("%d%d%d%d%d",&n,&m,S1,S2,&k);p=1ll*S1[0]*pow(S2[0])%mod;S1[0]=pow(mod+1-p,k);S2[0]=0;
		const int&q=1ll*p*pow(mod+1-p)%mod;for(int i=1;i<m;++i)S1[i]=1ll*S1[i-1]*q%mod;
		if(2*k<m)return printf("1"),void();if(p==1)return printf("0"),void();
		P[0]=P[1]=1;for(int i=2;i<m&&i<=k;++i)P[i]=1ll*(mod-mod/i)*P[mod%i]%mod;
		for(int i=1;i<m&&i<=k;++i)P[i]=1ll*(k-i+1)*P[i]%mod*P[i-1]%mod;
		for(int i=0;i<m;++i)P[i]=1ll*P[i]*S1[i]%mod;S1[0]=P[0];F[0]=1;
		for(int i=1;i<m;++i)S1[i]=(S1[i-1]+P[i])%mod;
		for(int k=1;k<=n;++k){
			const int&S(F[0]);for(int i=1;i<m;++i)S2[i]=(S2[i-1]+1ll*(mod-P[i])*F[m-i])%mod;
			for(int i=0;i<m;++i)G[i]=(1ll*(S+mod-F[m-i])*S1[m-i-1]+S2[m-i-1])%mod*P[i]%mod;
			for(int i=m-1;i>=0;--i)F[i]=(G[i]+F[i+1])%mod,G[i]=0;
		}
		printf("%d",F[0]);
	} 
}
signed main(){
	SOLVE::main();
}
posted @   Prean  阅读(46)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
var canShowAdsense=function(){return !!0};
点击右上角即可分享
微信分享提示