1. 程式人生 > 實用技巧 >CF708E Student's Camp

CF708E Student's Camp

CF708E Student's Camp [* easy]

有一個 \(n\times m\) 的矩形。

每天兩種操作,持續 \(k\) 天:

  • 所有最左邊的方塊有 \(p\) 的概率消失。
  • 所有最右邊的方塊有 \(p\) 的概率消失。

然後我們在最頂部和最底部增加一層,如果某個時刻,此圖分成了兩個聯通分量,那麼就 GG。

求不 GG 的概率。答案對 \(10^9+7\) 取模。

\(n,m\le 1500,k\le 10^5\)

Solution

考慮給每一行確定一個區間,合法當且僅當每個區間都和上一個區間相交。

\(f_{i,l,r}\) 表示考慮到第 \(i\) 行,區間為 \([l,r]\)

的概率和,由於 \([l,r]\) 的長度大於等於 \(1\),所以這件事發生的概率可以視為左邊走到 \(l\),右邊走到 \(r\) 的概率的乘積,即 \(p_l\times p_r\)

考慮轉移,形如:

\[f_{i,l,r}=p_lp_r\times \sum f_{i-1,l',r'}([l',r']\land [l,r]) \]

這樣難以優化,考慮減去不相交的區間,那麼後者只關乎區間的 \(r\) 端點,設 \(F_{i,R}=\sum f_{i,l,r}[r\le R],G_{i,L}=\sum f_{i,l,r}[l\ge L]\)

不難得到:

\[f_{i,l,r}=p_lp_r(\sum f-F_{i-1,l-1}-G_{i-1,r+1}) \]

然而複雜度還是太高了,考慮直接轉移 \(g_{i,r'}=\sum f_{i,l,r}[r=r']\),那麼就有:

\[g_{i,r}=p_r(\sum p_l(\sum f-F_{i-1,l-1}-G_{i-1,r+1})) \]

\[g_{i,r}=p_r(\sum p_l)(\sum f-G_{i-1,r+1})-p_r\sum p_lF_{i-1,l-1} \]

\[f_{i,l}=p_l(\sum p_r)(\sum f-F_{i-1,l-1})-p_l\sum p_rG_{i-1,r+1} \]

然後就可以算 \(G\) 了,類似處理 \(F\) 即可。

複雜度 \(\mathcal O(nm)\)

\(Code:\)

#include<bits/stdc++.h>
using namespace std ;
#define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
#define re register
#define int long long
int gi() {
	char cc = getchar() ; int cn = 0, flus = 1 ;
	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
	return cn * flus ;
}
const int P = 1e9 + 7 ; 
const int N = 1500 + 5 ; 
const int M = 1e5 + 5 ; 
int n, m, p, ip, t, h[N], H[N], F[N][N], G[N][N] ;
int f[N][N], g[N][N], pl[N], pr[N], fac[M], inv[M] ; 
int fpow(int x, int k) {
	if( k < 0 ) return 0 ; 
	int ans = 1, base = x ;
	while(k) {
		if(k & 1) ans = 1ll * ans * base % P ;
		base = 1ll * base * base % P, k >>= 1 ;
	} return ans ;
}
int C(int x, int y) {
	if(y > x || x < 0 || y < 0) return 0 ;
	return fac[x] * inv[y] % P * inv[x - y] % P ; 
}
signed main()
{
	n = gi(), m = gi() ; int x, y ; 
	x = gi(), y = gi(), p = x * fpow(y, P - 2) % P,
	t = gi(), fac[0] = inv[0] = 1, ip = (1 - p + P) % P ; 
	rep( i, 1, t ) fac[i] = fac[i - 1] * i % P, inv[i] = fpow(fac[i], P - 2) ; 
	rep( i, 1, m ) 
		pl[i] = C(t, i - 1) * fpow(p, i - 1) % P * fpow(ip, t - (i - 1)) % P, 
		pr[i] = C(t, m - i) * fpow(p, m - i) % P * fpow(ip, t - (m - i)) % P ;
	
	H[0] = 1 ; 
	rep( i, 1, n ) {
		int k = H[i - 1], d = 0, df = 0 ;
		rep( r, 1, m ) {
			d = (d + pl[r]) % P, df = (df + pl[r] * G[i - 1][r - 1]) % P,
			g[i][r] = pr[r] * d % P * (k - F[i - 1][r + 1] + P) % P,
			g[i][r] = (g[i][r] - pr[r] * df % P + P) % P ; //1/8
			//1/8
		}
		d = 0, df = 0 ; 
		for(re int l = m; l >= 1; -- l ) {
			d = (d + pr[l]) % P, df = (df + pr[l] * F[i - 1][l + 1]) % P, 
			f[i][l] = pl[l] * d % P * (k - G[i - 1][l - 1] + P) % P, 
			f[i][l] = (f[i][l] - pl[l] * df % P + P) % P ;
		}
		rep( r, 1, m ) G[i][r] = (G[i][r - 1] + g[i][r]) % P ;
		drep( l, 1, m ) F[i][l] = (F[i][l + 1] + f[i][l]) % P ; 
		H[i] = G[i][m] ;
	}
	cout << H[n] << endl ; 
	return 0 ;
}