CF708E Student's Camp
Problem
Analysis
正解思路
首先,分析题目的操作性质,发现每行最后形成的一定是一段区间。不妨考虑计算 \((l,r)\) 的形成概率,\(g_{l,r}=\binom{k}{l-1}p^{l-1}(1-p)^{k-l+1}\binom{k}{m-r}p^{m-r}(1-p)^{k+r-m}\)。
进一步考虑形成两个连通块的限制条件:两个连通的交接两行的最终区间无交。很容易去想到设计一个 dp:\(dp_{i,l,r}\) 为考虑前 \(i\) 行第 \(i\) 行状态为 \([l,r]\) 且最终不分裂的概率。转移比较显然 \(dp_{i,l,r}=g_{l,r}\sum_{[l',r']\cap [l,r]\ne\emptyset}dp_{i-1}\)。
可是,这是 \(O(nm^4)\) 的时间复杂度。考虑简单容斥,转移时用总方案减去非法方案,\(dp_{i,l,r}=g_{l,r}(\sum_{l'\le r'}dp_{i-1,l',r'}-\sum_{r'<l}dp_{i-1,l',r'}-\sum_{r<l'}dp_{i-1,l',r'})\)。
这三项分别写为 \(F_i=\sum_{l\le r}dp_{i,l,r}\),\(L_{i,j}=\sum_{l\le r<j}dp_{i,l,r}\) 和 \(R_{i,j}=\sum_{j<l\le r}dp_{i,l,r}\)。
所以 \(dp_{i,l,r}=g_{l,r}(F_{i-1}-L_{i-1,l}-R_{i-1,r})\)。
剩余的优化部分实在太 shit,请参考这篇题解。
错因总结
这题我也太糖了,我居然天真的以为只有缺失一行就会形成两个连通块,但其实只要相邻两行无交集就会形成两个连通块。
其实 dp 思路跟我想的差不多,再加前缀和优化就可过。
AC Code
点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define i128 __int128
#define fi first
#define se second
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define mk make_pair
#define INF 0x3f3f3f3f
#define INFx 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 1e5 + 10, M = 1510;
const int mod = 1e9 + 7;
int n, m, a, b, p, k;
int f[N], finv[N];
int D[M]; // D[i] = \binom{k}{i} * p^{i} * (1 - p)^{k - i}
int SD[M]; // SD[r] = \sum_{l = 1}^{r} D[l - 1]
int SDL[M]; // SDL[r] = \sum_{l = 1}^{r} D[l - 1] * L[i - 1][l]
int F[M]; // F[i] = sum_{r = 1}^{m} SL[i][r]
int L[M]; // L[x] = \sum_{r = 1}^{x - 1} SL[i][r]
int R[M]; // R[x] = L[i][m - x + 1]
int SL[M][M]; // SL[i][r] = D[m - r] * [(F[i - 1] - R[r]) * SD[r] - SDL[r]]
int fp(int a, int b) {
int mul = 1;
while (b) {
if (b & 1) mul = 1ll * mul * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return mul;
}
void init(int n) {
f[0] = finv[0] = 1;
for (int i = 1; i <= n; i ++) {
f[i] = 1ll * f[i - 1] * i % mod;
finv[i] = fp(f[i], mod - 2);
}
}
int C(int n, int m) {
if (n < m) return 0;
return 1ll * f[n] * finv[n - m] % mod * finv[m] % mod;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m >> a >> b >> k;
init(k);
p = 1ll * a * fp(b, mod - 2) % mod;
for (int i = 0; i <= min(m, k); i ++) {
D[i] = 1ll * C(k, i) * fp(p, i) % mod * fp((1 - p + mod) % mod, k - i) % mod;
}
SL[0][m] = 1;
// SD[r]
SD[0] = D[0];
for (int r = 1; r <= m; r ++) {
SD[r] = (1ll * SD[r - 1] + D[r]) % mod;
}
for (int i = 1; i <= n; i ++) {
// L[x] & R[x]
for (int x = 1; x <= m; x ++) {
L[x] = (1ll * L[x - 1] + SL[i - 1][x]) % mod;
R[m - x] = L[x];
}
// SDL[r]
for (int r = 1; r <= m; r ++) {
SDL[r] = (1ll * SDL[r - 1] + 1ll * D[r] * L[r] % mod) % mod;
}
// F[i]
for (int r = 1; r <= m; r ++) {
F[i] = (1ll * F[i] + SL[i - 1][r]) % mod;
}
// SL[i][r]
for (int r = 1; r <= m; r ++) {
int res = ((1ll * F[i] - R[r] + mod) % mod * SD[r - 1] % mod - SDL[r - 1] + mod) % mod;
SL[i][r] = 1ll * D[m - r] * res % mod;
}
}
int ans = 0;
for (int r = 1; r <= m; r ++) {
ans = (1ll * ans + SL[n][r]) % mod;
}
cout << ans << '\n';
return 0;
}

浙公网安备 33010602011771号