每行最后会剩下的显然是一个区间(可能为空),那么连通的条件即为每行剩余的区间非空,且相邻两行的区间均有交。
先预处理出最终某行某一侧恰好删去了
k
k
k个元素的概率。设
F
[
i
]
[
j
]
F[i][j]
F[i][j]表示仅考虑前
i
i
i行,它们连通且第
i
i
i行剩余区间的右端点为
j
j
j的概率,注意左右端点是对称的。直接转移有点吃力,可以考虑简单的容斥一下,用前
i
−
1
i-1
i−1行连通,且第
i
i
i行剩余区间左端点为
j
j
j的概率减去前
i
−
1
i-1
i−1行连通,第
i
i
i行剩余区间左端点为
j
j
j且第
i
i
i行和第
i
−
1
i-1
i−1行剩余区间没有交的概率。第二部分可以考虑第
i
−
1
i-1
i−1行剩余区间的情况,显然必有右端点
<
j
<j
<j或左端点
>
j
>j
>j之一满足,若左端点
>
j
>j
>j容易计算,右端点
<
j
<j
<j的话还需要考虑第
i
i
i行左端点的位置,稍微讨论一下容易用前缀和优化。
时间复杂度
O
(
n
m
+
k
)
\mathcal O(nm+k)
O(nm+k)。
#include <bits/stdc++.h>
#define MOD 1000000007
using namespace std;
typedef long long ll;
ll pow_mod(ll x,int k) {
ll ans=1;
while (k) {
if (k&1) ans=ans*x%MOD;
x=x*x%MOD;
k>>=1;
}
return ans;
}
inline void add(int &x,ll y) {
x=(x+y)%MOD;
}
inline void sub(int &x,ll y) {
x=(x-y)%MOD;
}
ll facd[100005],facv[100005];
ll val[2005],sum[2005];
inline ll C(int n,int m) {
return (n<m)?0:facd[n]*facv[m]%MOD*facv[n-m]%MOD;
}
void pre(int n,int k,ll p) {
facd[0]=1;
for(int i=1;i<=k;i++) facd[i]=facd[i-1]*i%MOD;
facv[k]=pow_mod(facd[k],MOD-2);
for(int i=k-1;i>=0;i--) facv[i]=facv[i+1]*(i+1)%MOD;
for(int i=0;i<=n;i++)
if (i<=k) val[i]=pow_mod(p,i)*pow_mod(1LL-p+MOD,k-i)%MOD*C(k,i)%MOD;
sum[0]=val[0];
for(int i=1;i<=n;i++) sum[i]=(sum[i-1]+val[i])%MOD;
}
int f[2005][2005],ans[2005];
int dp(int n,int m) {
for(int i=1;i<=m;i++) {
f[1][i]=val[m-i]*sum[i-1]%MOD;
add(ans[1],f[1][i]);
}
for(int i=2;i<=n;i++) {
for(int j=1;j<=m;j++) f[i][j]=ans[i-1]*val[m-j]%MOD*sum[j-1]%MOD;
int s1=0,s2=0;
for(int j=1;j<=m;j++) {
sub(f[i][j],s1*sum[j-1]%MOD*val[m-j]);
add(f[i][j],s2*val[m-j]);
add(s1,f[i-1][j]);
add(s2,f[i-1][j]*sum[j-1]);
}
int s=0;
for(int j=m;j>0;j--) {
sub(f[i][j],s*sum[j-1]%MOD*val[m-j]);
add(s,f[i-1][m-j+1]);
}
for(int j=1;j<=m;j++) add(ans[i],f[i][j]);
}
return (ans[n]+MOD)%MOD;
}
int main() {
int n,m,k;
ll p,q;
scanf("%d%d%lld%lld%d",&n,&m,&p,&q,&k);
p=p*pow_mod(q,MOD-2)%MOD;
pre(m,k,p);
printf("%d\n",dp(n,m));
return 0;
}