题解:CF2034F2 Khayyam's Royal Decree (Hard Version)
ForgetOIDuck · · 题解
我怎么只会
题意
有一个计数器,初始为
思路
首先我们要知道:从
由于每条路径概率相等,所以期望等于总和除以总方案数,而我们知道总方案数为
实际上我们不能直接算整张图每个点的总和,我们会发现最终影响答案或者被影响需要我们单独考虑计算的只有这
假设不考虑这些点
那么现在看看假设我们多了一个
首先我们计算
然后我们接着计算对
假设再增加一个
发现我们只需要维护
借此我们得到了这题的完整做法:
-
将
(r_i,b_i) 从大到小排序,保证如果按顺序从前往后计算的话能够更新到dp_i 的dp_j 都被计算过。 -
-
发现
(0,0) 的答案计算方式是和dp_i 一模一样的,于是我们为了方便可以把(0,0) 也当成一个关键点(r_{k+1},b_{k+1}) 统计答案。最后答案即为\dfrac{dp_{k+1}}{C_{n+m}^n} 。
时间复杂度
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
ll n, m, T, jc[500002], inv[500002], dp[502], k;
struct node {
ll r, b;
}p[502];
ll c(ll x, ll y) { // x 选 y 组合数
return jc[x] * inv[y] % mod * inv[x - y] % mod;
}
ll qmi(ll x, ll y) {
ll res = 1;
while (y) res = res * (y & 1 ? x : 1) % mod, x = x * x % mod, y >>= 1;
return res;
}
bool cmp(node az, node bz) {
return az.r > bz.r || (az.r == bz.r && az.b > bz.b);
}
int main() {
cin >> T;
jc[0] = 1;
for (ll i = 1; i <= 500000; i ++ ) jc[i] = jc[i - 1] * i % mod;
inv[500000] = qmi(jc[500000], mod - 2);
for (ll i = 499999; i >= 0; i -- ) inv[i] = inv[i + 1] * (i + 1) % mod;
//预处理阶乘及其逆元
while (T -- ) {
cin >> n >> m >> k;
for (ll i = 1; i <= k; i ++ ) dp[i] = 0, cin >> p[i].r >> p[i].b;
sort(p + 1, p + k + 1, cmp);
p[++ k] = {0, 0};
for (ll i = 1; i <= k; i ++ ) {
dp[i] = c(n + m - p[i].r - p[i].b, n - p[i].r) * (2 * (n - p[i].r) + (m - p[i].b)) % mod;
for (ll j = 1; j < i; j ++ ) if (p[j].r >= p[i].r && p[j].b >= p[i].b)
dp[i] = (dp[i] + c(p[j].r + p[j].b - p[i].r - p[i].b, p[j].r - p[i].r) * dp[j] % mod) % mod;
}
cout << dp[k] * qmi(c(n + m, n), mod - 2) % mod << "\n";
}
}