【题解】「CF708E」Student's Camp

传送门

题目大意:

(n+2)×m 的网格,每天在 2n+1 行最左边和最右边的格子都有 p 的概率会消失,问 k 天后第一行与最后一行仍旧能联通的概率。

n,m1.5×103,k105

题解:

考虑联通等价于存在一个从第一行到最后一行的路径,那么如果每种状态都能唯一对应一条路径,那么可以按照路径来dp。

钦定路径是能往下就往下,否则就往左/右走到第一个能往下的就往下。

fli,j 表示从 i1 行到 i,j 的位置时,向左走了若干步,同理 fri,jfdi,j 分别表示向右走了若干部以及直接往下,那么可以直接根据定义 O(nm2) 转移,可以前缀和优化到 O(nm)

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;
}
posted @   静谧时空  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示
主题色彩