ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF708E Student's Camp 题解

2022-05-28 11:01:47  阅读:132  来源: 互联网

标签:CF708E int 题解 sum Camp times read 丽莎 dp


题目大意

一个 \((n + 2) \times m\) 的网格。

除了第一行与最后一行,每一行都有 \(p\) 的概率消失,求 \(k\) 天后,网格始终保持联通的概率。

答案对 \(10^9 + 7\) 取模。

\(\text{Data Range:} 1 \leq n,m \leq 1.5 \times 10^3, k\leq 10^5\)。


不难发现最后每一行剩下的一定都会是一个连续的区间,而且每行之间相互独立。

自然设立状态 \(dp_{i,l,r}\) 表示当前是第 \(i\) 行,\(k\) 天后这一行剩下的区间为 \([l, r]\),第 \(0\) 行到第 \(i\) 行都联通的概率。

先考虑算变成区间 \([l,r]\) 的概率。

设 \(k\) 天内,消失 \(i\) 个格子的概率为 \(g_i = \binom{k}{i} p^i \times (1-p)^{k-i}\)。

所以剩下区间 \([l,r]\) 的概率为 \(g_{l-1} \times g_{m-r}\)。

当然还需要检查这段区间长度是否合法,因为最多消失 \(2k\) 个格子。

转移式子不难写出。

\[dp_{i,l,r} = g_{l-1} \times g_{m-r} \sum_{[l_1, r_1] \cap [l,r] \neq \varnothing} dp_{i-1,l_1,r_1} \]

复杂度 \(nm^4\),显然不行,而且状态数都为 \(nm^2\)。

那考虑优化状态,去掉左端点的限制。

设 \(dp_{i,r}\) 表示第 \(i\) 行的剩余区间的右端点为 \(r\),第 \(0\) 行到第 \(i\) 行都联通的概率,转移的时候枚举 \(l\) 进行转移。

考虑一个和区间 \([l,r]\) 有交的区间 \([l_1,r_1]\)。

它满足 \(r_1 \geq l, l_1 \leq r\),那么容斥把这一部分算出来即可。

对于 \(r_1 < l\) 的部分,枚举 \(l\) 时计算 \(\sum_{j=1}^{l-1} dp_{i-1,j}\)。

对于 \(l_1 > r\) 的部分,因为网格是对称的,所以 \(f_{i,r}\) 也可以表示左端点为 \(m-r+1\) 且联通的概率,因此这一部分可以计算为 \(\sum_{j=1}^{m-r} f_{i-1,j}\)。

于是转移如下。

\[dp_{i,r} = \sum_{l=1}^r g_{l-1} g_{m-r} (\sum_{j=1}^m f_{i-1, j} - \sum_{j = 1}^ {i-1} f_{i-1,j} - \sum_{j=1}^{m-r} f_{i-1,j}) \]

这东西长得就很一脸前缀和的样子,那就考虑前缀和优化。

令 \(s_{j}\) 表示 \(\sum_{k=1}^j f_{i-1,k}\)。

\[f_{i,r} = g_{m-r} \sum_{l=1}^r g_{l-1} )(s_m - s_{l-1} - s_{m-r}) \]

\[f_{i,r} = g_{m-r} \times( (s_m - s_{m-r}) \sum_{l = 1}^r g_{l-1} - \sum_{l=1}^r g_{l-1} s_{l-1}) \]

在令 \(p_i\) 和 \(q_i\) 依次为 \(g_i\) 与 \(g_i \times s_i\) 的前缀和,之后即可做到 \(O(1)\) 转移,总时间复杂度 \(o(nm)\)。

// 德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱
// 德丽莎的可爱在于德丽莎很可爱,德丽莎为什么很可爱呢,这是因为德丽莎很可爱!
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
  int x = 0, f = 1;  char ch = getchar();
  while( !isdigit(ch) ) { if(ch == '-') f = -1;  ch = getchar();  }
  while( isdigit(ch) ) {  x = (x << 1) + (x << 3) + (ch ^ 48);  ch = getchar();  }
  return x * f;
}
const int N = 3e6, mod = 1e9 + 7;
int n, m, a, b, pt, pt2, k, ans, fac[N], ifac[N], dp[3005][3005], g[3005];
int power(int a,int b) { int ans = 1; while (b) { if (b & 1) ans = ans * a % mod; a = a * a % mod; b >>= 1;} return ans; }
int binom(int n,int m) { return fac[n] * ifac[m] % mod * ifac[n - m] % mod; }
int s[N], p[N], q[N];
signed main () {
  n = read(), m = read(), a = read(), b = read(), k = read(); 
  fac[0] = 1; for (int i = 1; i <= k; i++) fac[i] = fac[i - 1] * i % mod;
  ifac[k] = power(fac[k], mod - 2); for (int i = k - 1; ~i; i--) ifac[i] = ifac[i + 1] * (i + 1) % mod;
  pt = a * power(b, mod - 2) % mod; pt2 = 1 - pt; pt2 += mod; pt2 %= mod;
  for (int i = 0; i <= k && i <= m; i++) g[i] = binom(k, i) * power(pt, i) % mod * power(pt2, k - i) % mod;
  dp[0][m] = 1;  p[0] = g[0]; 
  for (int i = 1; i <= m; i++) p[i] = p[i - 1] + g[i], p[i] %= mod;
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) s[j] = s[j - 1] + dp[i - 1][j], s[j] %= mod;
    for (int j = 1; j <= m; j++) q[j] = q[j - 1] + g[j] * s[j] % mod, q[j] %= mod;
    for (int r = 1; r <= m; r++) dp[i][r] = g[m - r] * ( (s[m] - s[m - r] + mod) % mod * p[r - 1] % mod - q[r - 1] + mod) % mod;
  }  
  for (int i = 1; i <= m; i++) { ans += dp[n][i]; ans %= mod;}
  printf("%lld\n", ans);
  return 0;
}

标签:CF708E,int,题解,sum,Camp,times,read,丽莎,dp
来源: https://www.cnblogs.com/orzpls/p/16320049.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有