【思路要点】
- 首先,定义 ttt 次成功率为 ppp 的操作恰好成功 xxx 次的概率为 ft,p(x)f_{t,p}(x)ft,p(x) ,有 ft,p(x)=px(1−p)t−x(tx)f_{t,p}(x)=p^x(1-p)^{t-x}\binom{t}{x}ft,p(x)=px(1−p)t−x(xt) 。
- 对于任意一行,留下的部分是区间 [l,r][l,r][l,r] 的概率为 ft,p(l−1)∗ft,p(M−r)f_{t,p}(l-1)*f_{t,p}(M-r)ft,p(l−1)∗ft,p(M−r) 。
- 考虑一个直观的 O(NM2)O(NM^2)O(NM2) 的动态规划做法,记 dpi,j,kdp_{i,j,k}dpi,j,k 表示前 iii 行连通,并且第 iii 行留下的区间为 [j,k][j,k][j,k] 的概率,记 prei,x=∑j=1x∑k=jxdpi,j,k,sufi,x=∑j=xM∑k=jMdpi,j,kpre_{i,x}=\sum_{j=1}^{x}\sum_{k=j}^{x}dp_{i,j,k},suf_{i,x}=\sum_{j=x}^{M}\sum_{k=j}^{M}dp_{i,j,k}prei,x=∑j=1x∑k=jxdpi,j,k,sufi,x=∑j=xM∑k=jMdpi,j,k ,显然有转移 dpi,j,k=ft,p(j−1)∗ft,p(M−k)∗(prei−1,M−prei−1,j−1−sufi−1,k+1)dp_{i,j,k}=f_{t,p}(j-1)*f_{t,p}(M-k)*(pre_{i-1,M}-pre_{i-1,j-1}-suf_{i-1,k+1})dpi,j,k=ft,p(j−1)∗ft,p(M−k)∗(prei−1,M−prei−1,j−1−sufi−1,k+1) 。
- 我们发现转移时并不需要知道 dpi,j,kdp_{i,j,k}dpi,j,k ,只需要知道 prei,xpre_{i,x}prei,x 和 sufi,xsuf_{i,x}sufi,x 即可。
- 考虑直接利用 prei,xpre_{i,x}prei,x 和 sufi,xsuf_{i,x}sufi,x 进行动态规划,以计算 prei,xpre_{i,x}prei,x 为例,记 prei,x′=∑j=1xdpi,j,xpre'_{i,x}=\sum_{j=1}^{x}dp_{i,j,x}prei,x′=∑j=1xdpi,j,x ,显然 prei,xpre_{i,x}prei,x 就是 prei,x′pre'_{i,x}prei,x′ 的前缀和。那么根据上面的计算式,有 prei,k′=∑j=1kft,p(j−1)∗ft,p(M−k)∗(prei−1,M−prei−1,j−1−sufi−1,k+1)pre'_{i,k}=\sum_{j=1}^{k}f_{t,p}(j-1)*f_{t,p}(M-k)*(pre_{i-1,M}-pre_{i-1,j-1}-suf_{i-1,k+1})prei,k′=∑j=1kft,p(j−1)∗ft,p(M−k)∗(prei−1,M−prei−1,j−1−sufi−1,k+1) ,可以发现,若将括号拆开,每一项都可以表示为只和 i,ki,ki,k 相关的一个量乘以只和 i,ji,ji,j 相关的一个量,可以通过部分和进行优化。
- 时间复杂度为 O(NM+T)O(NM+T)O(NM+T) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXM = 2e5 + 5; const int MAXN = 3005; const int P = 1e9 + 7; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } int pre[2][MAXN], suf[2][MAXN]; int n, m, p, q, t, lp[MAXN], rp[MAXN]; int fac[MAXM], inv[MAXM], powp[MAXM], powq[MAXM]; void update(int &x, int y) { x = (x + y >= P) ? (x + y - P) : (x + y); } void getdp() { static int sumlp[MAXN], sumrp[MAXN]; for (int i = 1; i <= m; i++) { sumlp[i] = (sumlp[i - 1] + lp[i]) % P; pre[1][i] = 1ll * sumlp[i] * rp[i] % P; update(pre[1][i], pre[1][i - 1]); } for (int i = m; i >= 1; i--) { sumrp[i] = (sumrp[i + 1] + rp[i]) % P; suf[1][i] = 1ll * sumrp[i] * lp[i] % P; update(suf[1][i], suf[1][i + 1]); } for (int i = 2, now = 0, from = 1; i <= n; i++, swap(now, from)) { int tmp = 0; for (int j = 1; j <= m; j++) { pre[now][j] = 1ll * sumlp[j] * pre[from][m] % P; update(tmp, 1ll * pre[from][j - 1] * lp[j] % P); update(pre[now][j], P - tmp); update(pre[now][j], P - 1ll * sumlp[j] * suf[from][j + 1] % P); pre[now][j] = 1ll * pre[now][j] * rp[j] % P; update(pre[now][j], pre[now][j - 1]); } tmp = 0; for (int j = m; j >= 1; j--) { suf[now][j] = 1ll * sumrp[j] * pre[from][m] % P; update(tmp, 1ll * suf[from][j + 1] * rp[j] % P); update(suf[now][j], P - tmp); update(suf[now][j], P - 1ll * sumrp[j] * pre[from][j - 1] % P); suf[now][j] = 1ll * suf[now][j] * lp[j] % P; update(suf[now][j], suf[now][j + 1]); } } } int power(int x, int y) { if (y == 0) return 1; int tmp = power(x, y / 2); if (y % 2 == 0) return 1ll * tmp * tmp % P; else return 1ll * tmp * tmp % P * x % P; } int getc(int x, int y) { if (y > x) return 0; else return 1ll * fac[x] * inv[y] % P * inv[x - y] % P; } int getp(int x) { return 1ll * getc(t, x) * powp[x] % P * powq[t - x] % P; } void init(int n) { fac[0] = powp[0] = powq[0] = 1; for (int i = 1; i <= n; i++) { fac[i] = 1ll * fac[i - 1] * i % P; powp[i] = 1ll * powp[i - 1] * p % P; powq[i] = 1ll * powq[i - 1] * q % P; } inv[n] = power(fac[n], P - 2); for (int i = n - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1ll) % P; for (int i = 1; i <= m; i++) { lp[i] = getp(i - 1); rp[i] = getp(m - i); } } int main() { freopen("chocolate.in", "r", stdin); freopen("chocolate.out", "w", stdout); read(n), read(m); read(p), read(q); p = 1ll * p * power(q, P - 2) % P; q = (P + 1 - p) % P; read(t), init(t), getdp(); printf("%d\n", pre[n & 1][m]); return 0; }