P13606 [NWRRC 2022] IQ Game
首先化简一下题目,直接钦定最难题放到 \(n\) 的位置上,这样不影响相对顺序和答案,然后做题的期望轮数就等于结束之前做了 \(k\) 题的概率之和。
观察题目的操作,会把如果两个相邻题前面分别有 \(a - 1, b - 1\) 个空位,那么解决第一个之后前面就会有 \(a + b - 1\),这和石子合并很相似,可以看作两个区间被合并起来了。
最后除了包含 \(n\) 的区间,操作其它区间都不会影响包含 \(n\) 的区间,所以我们对每个区间单独考虑,最后用组合数把操作合并起来。
设 \(f_{l, r}\) 表示区间 \([l, r]\) 的题做了的概率,转移枚举最后一个做的题是哪题,然后左右概率乘起来再乘上做到这道题的概率。
最后用一个 DP \(g_{i, j}\) 表示前 \(i\) 道题,做了 \(j\) 题的概率,这是一个背包,不过最后一步要乘上完成 \(n\) 的概率。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <set>
#define int long long
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 200 + 10, M = 1e5, mod = 998244353;
int ans, fac[N], ifac[N], f[N][N], g[N][N], a[N], n, m, T;
int qmi(int a, int b) {
int res = 1;
while(b) {
if(b & 1) res = res * a % mod;
a = a * a % mod, b >>= 1;
}
return res;
}
int C(int n, int m) {
if(n < m || n < 0 || m < 0) return 0;
return fac[n] * ifac[m] % mod * ifac[n - m] % mod;
}
int F(int l, int r) {
return (a[r] - a[l - 1]) * qmi(n, mod - 2) % mod;
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m >> T;
fac[0] = ifac[0] = 1;
for(int i = 1; i < N; i ++) fac[i] = fac[i - 1] * i % mod;
ifac[N - 1] = qmi(fac[N - 1], mod - 2);
for(int i = N - 2; i; i --) ifac[i] = ifac[i + 1] * (i + 1) % mod;
for(int i = 1; i <= m; i ++) cin >> a[i];
T -= a[1] - 1;
for(int i = m; i; i --) a[i] -= a[1] - 1;
for(int i = 1; i <= m; i ++) if(a[i] <= T) a[i] = n - (T - a[i]); else a[i] = a[i] - T;
sort(a + 1, a + m + 1);
a[0] = 0;
for(int i = 1; i <= m + 1; i ++) f[i][i - 1] = 1;
for(int len = 1; len <= m; len ++) {
for(int i = 1; i + len - 1 <= m; i ++) {
int j = i + len - 1;
for(int k = i; k <= j; k ++) {
f[i][j] = (f[i][k - 1] * f[k + 1][j] % mod * C(j - i, k - i) % mod * F(i, k) % mod + f[i][j]) % mod;
}
// cout << i << ' ' << j << ' ' << f[i][j] << '\n';
}
}
g[0][0] = 1;
for(int i = 0; i < m; i ++) {
for(int j = 0; j <= m; j ++) {
if(!g[i][j]) continue;
for(int k = i + 1; k <= m; k ++) {
int vl = g[i][j] * f[i + 1][k - 1] % mod * C(j + k - i - 1, k - i - 1) % mod;
if(k == m) vl = vl * F(i + 1, m) % mod;
(g[k][j + k - i - 1] += vl) %= mod;
}
// cout << i << ' ' << j <<' '<< g[i][j] << '\n';
}
}
int ans = 0;
for(int j = 0; j <= m; j ++) ans = (ans + g[m][j] * (j + 1)) % mod;
cout << ans << '\n';
return 0;
}

希罗神颜
浙公网安备 33010602011771号