下笔春蚕食叶声。

CF708E Student's Camp

CF708E Student's Camp

看题解人 所以本地写了一遍然后放在cnblog上选了“只有我”的权限在cnblog修好后会不会显示。。。

网格始终保持联通,等价于要求 \(k\) 天后,任意相邻两行剩下的区间有交。

\(f_{i,l,r}\) 表示 \(1\)\(i\) 行符合要求且第 \(i\) 行剩下的砖是 \([l,r]\) 的概率。

考虑风对于指定的某一行的某一边吹掉 \(i\) 块砖的概率:

\[D(i)={k\choose i }p^i(1-p)^{k-i} \]

考虑特定的一行剩下 \([l,r]\) 的概率:

\[P(l,r)=D(l-1)D(m-r) \]

考虑计算 \(f_{i,l,r}\)

\[f_{i,l,r}=P(l,r)\sum_{[l',r']∩[l,r]\neq ∅}f_{i-1,l',r'}\\ f_{i,l,r}=D(l-1)D(m-r)(\sum_{l'\le r'} f_{i-1,l',r'}-\sum_{r'<l} f_{i-1,l',r'}-\sum_{l'>r} f_{i-1,l',r'}) \]

复杂度 \(O(nm^2)\) 需要优化。

\[F(i)=\sum_{l\le r} f_{i,l,r}\\ L(i,x)=\sum_{l\le r<x} f_{i,l,r}=\sum_{r=1}^{x-1} \sum_{l=1}^r f_{i,l,r}\\ R(i,x)=\sum_{r\ge l>x} f_{i,l,r}=\sum_{l=x+1}^m \sum_{r=l}^m f_{i,l,r}\\ f_{i,l,r}=D(l-1)D(m-r)(F(i-1)-L(i-1,l)-R(i-1,t))\\ \]

显然 \(L\)\(R\) 非常对称。 \(L(i,x)=R(i,m+1-x)\) 因此这里只考虑 \(L\) 的求解。

\(S_L(i,r)\) 为右端点为 \(r\)\(f_{i,l,r}\) 之和。

\[L(i,x)=\sum_{r=1}^{x-1} S_L(i,r) \\F(i)=\sum_{r=1}^m S_L(i,r) \]

\[\begin{aligned} S_L(i,r)&=\sum_{l\le r} f_{i,l,r}\\ &=\sum_{l\le r} D(l-1)D(m-r)(F(i-1)-L(i-1,l)-R(i-1,r))\\ &=D(m-r)\sum_{l\le r} D(l-1)(F(i-1)-L(i-1,l)-R(i-1,r))\\ &=D(m-r)( \ (F(i-1)-R(i-1,r))\sum_{l\le r} D(l-1)-\sum_{l\le r} (D(l-1)L(i-1,l))\ ) \end{aligned} \]

因此对 \(D(l-1)\)\(D(l-1)L(i-1,l)\) 做前缀和 ,计算出 \(S_L(i,r)\) ,计算出 \(L(i,l)\),以此类推,直到算出最终答案。

时间复杂度 \(O(nm)\) ,空间复杂度通过滚动可以优化为 \(O(m)\) (可以,但没必要)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1510,K=100010,mod=1e9+7;
int n,m,a,b,k;
int tmpp[K],tmp1p[K],C[K],d[K],sum[K];
int sumdl[N],tmpsum[N],s[N][N],F[N],L[N][N];
int power(int x,int y){
	int ret=1;
	while(y){
		if(y&1) ret=1ll*ret*x%mod;
		x=1ll*x*x%mod; y>>=1;
	}
	return ret;
}
int main(){
//	freopen("ex.in","r",stdin);
	//freopen("ex.out","w",stdout);
	scanf("%d%d%d%d%d",&n,&m,&a,&b,&k);
	int p=1ll*a*power(b,mod-2)%mod;
	tmpp[0]=tmp1p[0]=C[0]=1;
	for(int i=1;i<=k;i++){
		tmpp[i]=1ll*tmpp[i-1]*p%mod;
		tmp1p[i]=1ll*tmp1p[i-1]*((1+mod-p)%mod)%mod;
	}
	for(int i=0;i<=min(m,k);i++){
		if(i) C[i]=1ll*(k-i+1)*power(i,mod-2)%mod*C[i-1]%mod;
		d[i]=1ll*C[i]*tmpp[i]%mod*tmp1p[k-i]%mod;
	}
	for(int i=0;i<=m;i++) sum[i]=(i)?((sum[i-1]+d[i])%mod):d[i];
	s[0][m]=1; F[0]=1; 
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			int tmp=(1ll*((F[i-1]+mod-L[i-1][m+1-j])%mod)*sum[j-1]%mod+mod-sumdl[j])%mod;
			s[i][j]=1ll*d[m-j]*tmp%mod;
			tmpsum[j]=(tmpsum[j-1]+s[i][j])%mod;
			//求s
		}
		for(int j=1;j<=m;j++){
			L[i][j]=tmpsum[j-1];
			sumdl[j]=(sumdl[j-1]+1ll*d[j-1]*L[i][j]%mod)%mod;
		}
		F[i]=tmpsum[m];
	}
	printf("%d\n",F[n]);
	return 0;
}
posted @ 2021-03-23 17:44  ACwisher  阅读(29)  评论(0编辑  收藏  举报