1. 程式人生 > 其它 >Codeforces708E Student's Camp

Codeforces708E Student's Camp

Description

有一個 \((n+2) \times m\) 的網格。

除了第一行和最後一行,其他每一行每一天最左邊和最右邊的格子都有 \(p\) 的概率消失。

\(k\) 天后,網格始終保持連通的概率。

\(n,m \le 1.5 \times 10^3\)\(k \le 10^5\),答案對 \(10^9+7\) 取模。

Solution

先計算 \(\displaystyle P_i=\binom Ki(1-p)^{K-i}p^i\) 表示經過 \(k\) 天后在單個方向有 \(i\) 個格子消失的概率

那麼設 \(f_{i,l,r}\) 表示第 \(i\) 行剩下 \(l,r\)

且保證連通到第一行的概率,轉移找上一行有交的就行了

\(L_{i,j}\) 表示第 \(i\) 行右端點不超過 \(j\) 的所有區間 \(f\) 值之和,\(R_{i,j}\) 表示左端點不小於 \(j\) 的區間 \(f\) 值之和

由於矩形是對稱的,那麼 \(L_{i,j}=R_{i,m-j+1}\)

單個元素轉移複雜度難以下降,同時對每個元素各自進行觀察除了對稱什麼也得不到,所以只能嘗試摸索字首和轉移是否可行

將單個元素轉移式對兩側第二維求和得到

\[F_{i,r}=\sum_{l\le r}(S_{i-1}-L_{i-1,l-1}-L_{i-1,m-r})E_{l-1}E_{m-r} \]

其中 \(S_{i}\)

表示第 \(i\) 行所有元素的 \(\rm dp\) 值求和的結果,拆開分別做字首和即可

時間複雜度 \(\Theta(mn)\)

Code

const int N=2010;
int n,p,c[N],d[N][N],dp[N];
signed main(){
	n=read();
	int a=read(),b=read();
	p=mul(a,ksm(b,mod-2));
	d[1][0]=d[1][1]=1;
	for(int i=2;i<=n;i++){
		d[i][0]=1;
		for(int j=1;j<=i;j++)
			d[i][j]=(d[i-1][j]*ksm(mod+1-p,j)+d[i-1][j-1]*ksm(p,i-j))%mod;
	}
	for(int i=1;i<=n;i++){
		int res=0;
		for(int j=1;j<i;j++) ckadd(res,mul(c[j],d[i][j]));
		c[i]=del(1,res);
	}
	for(int i=1;i<=n;i++){
		int res=0;
		for(int j=1;j<i;j++){
			int tmp=(dp[j]+j*(i-j)+dp[i-j]+j*(j-1)/2)%mod;
			res=(res+c[j]*d[i][j]%mod*tmp)%mod;
		}
		res=(res+c[i]*d[i][i]%mod*(i*(i-1)/2))%mod;
		dp[i]=res*ksm(mod+1-c[i]*d[i][i]%mod,mod-2)%mod;
	}
	print(dp[n]);
	return 0;
}