CF708E Student's Camp

Student's Camp

有一个 \((n + 2) × m\) 的长方形,除了第一行和最后一行,其他每一行每一天最左边和最右边未被摧毁的格子都有概率 \(P\) 被摧毁(每天概率相同),每行之间独立且左边和右边独立,求 \(k\) 天之后最上面一行与最下面一行四联通的概率。

答案对 \(10^9 + 7\) 取模。

\(n, m ≤ 1500\)

题解

https://www.luogu.com.cn/blog/hotwords/solution-cf708e

首先转化题意。题目中已经限定了最高和最低一行的方块不会被吹走,所以整个建筑「不连通」只可能是被「上下劈开」,不可能是被「左右劈开」。也就是说,整个建筑「连通」,当且仅当对于所有相邻的两行,它们最后剩下的方块连通。

考虑 DP。设 \(f(i,l,r)\) 表示第 \(i\) 行剩下 \([l,r]\) 的方块且建筑不倒的概率。

先考虑某一行剩下 \([l,r]\) 的方块的概率。

\(D(i)\) 表示 \(k\) 次「吹风」中 \(i\) 次成功的概率,显然

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

可以 \(O(k)\) 预处理求出所有的 \(D(i)\)

\(P(l,r)\ (1 \le l \le r \le m)\) 表示某一行只剩下 \([l,r]\) 的砖块的概率,由于左右两边相互独立,可以得到 $$ P(l,r) = D(l-1) D(m-r) $$

接下来考虑如何从第 \(i-1\) 行转移。

由前面的分析,第 \(i\) 行最后剩下的方块所占的区间要和第 \(i-1\) 行的区间有交,即

\[f(i,l,r) = P(l,r) \sum_{[l',r']\cap[l,r] \ne \varnothing} f(i-1,l',r') \]

边界是 \(f(0,1,m) = 1\) ,答案即为所有 \(f(n,l,r)\) 的和。

这样状态数为 \(O(nm^2)\) ,转移复杂度 \(O(m^2)\) ,需要优化。

考虑问题的反面,即 \([l,r]\)\([l',r']\) 没有交集。容易发现,这只有两种互斥的情况:要么 \(r' \lt l\) ,要么 \(l' \gt r\)

于是,我们得到:

\[f(i,l,r) = P(l,r) \left[ \sum_{l' \le r'} f(i-1,l',r') - \sum_{r' \lt l} f(i-1,l',r') - \sum_{l' \gt r} f(i-1,l',r') \right] \]

发现只要求出三个求和号的部分就能转移了,即

\[\begin{aligned} F(i) &= \sum_{l \le r} f(i,l,r) \\ L(i,x) &= \sum_{l \le r \lt x} f(i,l,r) \\ R(i,x) &= \sum_{r \ge l \gt x} f(i,l,r) \\ f(i,l,r) &= P(l,r) \Big[ F(i-1) - L(i-1,l) - R(i-1,r) \Big] \end{aligned} \]

注意其中 \(F(i)\) 的意义,它表示前 \(i\) 行连通的概率,那么答案就是 \(F(n)\)

细心的同学可能已经发现了, \(L(i,x)\)\(R(i,x)\) 在转移、形式和结果上都是高度对称的。事实上,把 \(L(i,x)\) 左右翻转就可以得到 \(R(i,x)\) ,即 \(L(i,x)=R(i,m-x+1)\) 。于是我们只要讨论 \(L(i,x)\) 的处理就可以了。

由于 \(f(i,l,r)\) 会对所有 \(x \gt r\)\(L(i,x)\) 产生贡献,我们可以先记 \(S_L(i,r)\) 表示所有右端点为 \(r\)\(f(i,l,r)\) 之和,则对 \(S_L\) 计算前缀和即可得到 \(L\) ,用公式表达就是:

\[\begin{aligned} S_L(i,r) &= \sum_{l \le r} f(i,l,r) \\ L(i,x) &= \sum_{r \lt x} S_L(i,r) \end{aligned} \]

同时我们可以发现,所有的 \(S_L(i,r)\) 之和就等于 \(F(i)\) ,这样就把 \(F(i)\) 也一并解决了。

接下来考虑如何计算 \(S_L(i,r)\) ,把 \(f(i,l,r)\) 的转移式代入:

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

到这里思路已经很清晰了,对 \(D(l-1)\)\(D(l-1) L(i-1,l)\) 做前缀和即可实现 \(O(1)\) 转移,最后答案即为 \(F(n)\) 。边界同样是 \(f(0,1,m)=1\) ,即 \(S_L(0,m)=1\)

总时间复杂度 \(O(nm+k)\) ,空间复杂度可以用滚动数组优化至 \(O(m+k)\)

CO int N=1.5e3+10,M=1e5+10;
int fac[M],ifac[M];
int D[N],sumD[N];
int f[N][N];

IN int C(int n,int m){
	return mul(fac[n],mul(ifac[m],ifac[n-m]));
}
int main(){
	int n=read<int>(),m=read<int>();
	int A=read<int>(),B=read<int>(),P=mul(A,fpow(B,mod-2));
	int K=read<int>();
	fac[0]=1;
	for(int i=1;i<=K;++i) fac[i]=mul(fac[i-1],i);
	ifac[K]=fpow(fac[K],mod-2);
	for(int i=K-1;i>=0;--i) ifac[i]=mul(ifac[i+1],i+1);
	for(int i=0;i<=m and i<=K;++i)
		D[i]=mul(C(K,i),mul(fpow(P,i),fpow(1+mod-P,K-i)));
	sumD[0]=D[0];
	for(int i=1;i<=m;++i) sumD[i]=add(sumD[i-1],D[i]);
	f[0][m]=1;
	for(int i=1;i<=n;++i){
		int tot=f[i-1][m];
		int DL=0;
		for(int j=1;j<=m;++j){
			DL=add(DL,mul(D[j-1],f[i-1][j-1]));
			int tmp=add(mul(tot+mod-f[i-1][m-j],sumD[j-1]),mod-DL);
			f[i][j]=add(f[i][j-1],mul(D[m-j],tmp));
		}
	}
	printf("%d\n",f[n][m]);
	return 0;
}

posted on 2020-04-22 16:04  autoint  阅读(186)  评论(0编辑  收藏  举报

导航