【题解】「CF708E」Student's Camp
题目大意:
有 的网格,每天在 行最左边和最右边的格子都有 的概率会消失,问 天后第一行与最后一行仍旧能联通的概率。
。
题解:
考虑联通等价于存在一个从第一行到最后一行的路径,那么如果每种状态都能唯一对应一条路径,那么可以按照路径来dp。
钦定路径是能往下就往下,否则就往左/右走到第一个能往下的就往下。
令 表示从 行到 的位置时,向左走了若干步,同理 和 分别表示向右走了若干部以及直接往下,那么可以直接根据定义 转移,可以前缀和优化到 。
Code
#include <bits/stdc++.h>
#define FOR(i,j,k) for(int i=j; i<=k; ++i)
#define ROF(i,j,k) for(int i=j; i>=k; --i)
inline int read (void) {
int x = 0, f = 1, ch = getchar();
while(!isdigit(ch)) { if(ch == '-') f = -f; ch = getchar(); }
while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
using ll = long long;
const int maxn = 1505;
const int maxk = 100005;
const int mod = 1000000007;
inline int ksm (int a, int b) {
int c = 1;
while(b) {
if(b&1) c = 1ll * c * a % mod;
a = 1ll * a * a % mod; b >>= 1;
} return c;
}
int fac[maxk], inv[maxk];
inline int binom (int n, int m) {
return n < m || m < 0 ? 0 : 1ll * fac[n] * inv[m] % mod * inv[n-m] % mod;
}
int f[maxk], g[maxk], fl[maxn][maxn], fr[maxn][maxn], fd[maxn][maxn];
int main (void) {
fac[0] = 1; FOR(i,1,100000) fac[i] = 1ll * fac[i-1] * i % mod;
inv[100000] = ksm (fac[100000], mod-2); ROF(i,100000,1) inv[i-1] = 1ll * inv[i] * i % mod;
int n = read(), m = read(), a = read(), b = read(), t = read();
int p = 1ll * a * ksm (b, mod-2) % mod;
FOR(i,0,t) f[i] = 1ll * ksm (p, i) * ksm (mod+1-p, t-i) % mod * binom (t, i) % mod;
g[0] = f[0]; FOR(i,1,std::max(t, m)) g[i] = (g[i-1] + f[i]) % mod;
FOR(k,2,m) fr[1][k] = f[k-1]; fd[1][1] = 1; int s;
FOR(i,1,n-1) {
s = 0;
FOR(k,1,m) {
fr[i+1][k] = 1ll * f[k-1] * g[m-k] % mod * s % mod;
s = ((ll) s + fr[i][k] + 1ll * fd[i][k] * g[k-1]) % mod;
}
FOR(j,1,m) {
fd[i+1][j] = (fd[i+1][j] + 1ll * fl[i][j] * g[j-1]) % mod;
fd[i+1][j] = (fd[i+1][j] + 1ll * fd[i][j] * g[j-1] % mod * g[m-j]) % mod;
fd[i+1][j] = (fd[i+1][j] + 1ll * fr[i][j] * g[m-j]) % mod;
}
s = 0;
ROF(k,m,1) {
fl[i+1][k] = 1ll * f[m-k] * g[k-1] % mod * s % mod;
s = ((ll) s + fl[i][k] + 1ll * fd[i][k] * g[m-k]) % mod;
}
}
// FOR(i,0,n-1) {
// FOR(j,1,m) FOR(k,j+1,m) {
// fr[i+1][k] = (fr[i+1][k] + 1ll * fr[i][j] * f[k-1] % mod * (i == 0 ? 1 : g[m-k])) % mod;
// fr[i+1][k] = (fr[i+1][k] + 1ll * fd[i][j] * f[k-1] % mod * (i == 0 ? 1 : g[m-k]) % mod * (i == 0 ? 1 : g[j-1])) % mod;
// }
// FOR(j,1,m) {
// fd[i+1][j] = (fd[i+1][j] + 1ll * fl[i][j] * (i == 0 ? 1 : g[j-1])) % mod;
// fd[i+1][j] = (fd[i+1][j] + 1ll * fd[i][j] * (i == 0 ? 1 : g[j-1]) % mod * (i == 0 ? 1 : g[m-j])) % mod;
// fd[i+1][j] = (fd[i+1][j] + 1ll * fr[i][j] * (i == 0 ? 1 : g[m-j])) % mod;
// }
// FOR(j,1,m) FOR(k,1,j-1) {
// fl[i+1][k] = (fl[i+1][k] + 1ll * fl[i][j] * f[m-k] % mod * (i == 0 ? 1 : g[k-1])) % mod;
// fl[i+1][k] = (fl[i+1][k] + 1ll * fd[i][j] * f[m-k] % mod * (i == 0 ? 1 : g[k-1]) % mod * (i == 0 ? 1 : g[m-j])) % mod;
// }
// }
int ans = 0;
FOR(j,1,m) {
ans = (ans + 1ll * fl[n][j] * g[j-1]) % mod;
ans = (ans + 1ll * fr[n][j] * g[m-j]) % mod;
ans = (ans + 1ll * fd[n][j] * g[j-1] % mod * g[m-j]) % mod;
}
printf("%d\n", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通