CF1153F - Serval and Bonus Problem(概率dp)
题意
有一段长为\(l\)的线段,有\(n\)个区间,左右端点在\([0,l)\)间均匀随机(可能不是整数)
求被至少\(k\)段区间覆盖的长度的期望,对998244353取膜
题解
首先先令\(l=1\),最后答案再乘回去即可。
故题目变为在长度为1的线段中被至少k个随机区间覆盖的区域长度。等价于在\([0,1)\)中随机选一个点\(x\),\(x\)至少被k个随机区间覆盖的概率。关键在于这里问题的转化。
那么就可以算\(x\)被覆盖的方案数了。随机取\(n\)个区间,会产生\(2n\)个端点,加上点\(x\),一共有\(2n+1\)个点。这些点都是独立随机取的。事实上,这\(2n+1\)个点的取值不重要,重要的是它们的顺序。因为把这些点按照大小排序,就是一个排列(两个点在同一个位置的概率为0)。因此问题转换为有多少长度为\(2n+1\)的排列,使得\(x\)在至少k对点对之中。
设\(dp[i][j][x]\)代表已经选择了\(i\)个点,未选点中有\(j\)个点未和前\(i\)个点匹配(即已经有\(\frac{i-j}{2}\)对区间配对好了),其中\(x=\{0,1\}\),代表点\(x\)已经被选过了。
转移(当前在\(i\)):
- 如果\(j \ge k\),那么当前位置可以放\(x\),这样\(x\)就被大于等于\(k\)的区间包含了。
\[dp[i-1][j][0]\to dp[i][j][1]
\]
- 当前位置放的是未匹配点,未匹配点就少1,这样的点有\(j+1\)个。
\[(j+1)\cdot dp[i-1][j+1][x] \to dp[i][j][x]
\]
- 当前位置放的不是未匹配的点,会导致未匹配点多1。这样点有\(2n-(i-1)-(j-1)+x\)个
\[\max(0,2n-(i-1)-(j-1)+x)\cdot dp[i-1][j-1][x] \to dp[i][j][x]
\]
最后合法方案数为\(dp[2n+1][0][1]\),总方案数为\((2n+1)!\),答案为
\[\frac{dp[2n+1][0][1]}{(2n+1)!}\cdot l
\]
#include <bits/stdc++.h>
#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
const int N = 4e3 + 10;
const int M = 998244353;
const double eps = 1e-5;
int dp[N][N][2], fact[N];
inline ll qmul(ll a, ll b, ll m) {
ll res = 0;
while(b) {
if(b & 1) res = (res + a) % m;
a = (a << 1) % m;
b = b >> 1;
}
return res;
}
inline ll qpow(ll a, ll b, ll m) {
ll res = 1;
while(b) {
if(b & 1) res = (res * a) % m;
a = (a * a) % m;
b = b >> 1;
}
return res;
}
int main() {
IOS;
fact[0] = 1;
for(int i = 1 ; i < N; i++) {
fact[i] = 1ll * fact[i - 1] * i % M;
}
int n, k, l;
cin >> n >> k >> l;
dp[0][0][0] = 1;
for(int i = 1; i <= 2 * n + 1; i++) {
for(int j = 0; j <= i; j++) {
if(j >= k) {
dp[i][j][1] += dp[i - 1][j][0];
dp[i][j][1] %= M;
}
dp[i][j][0] += 1ll * dp[i - 1][j + 1][0] * (j + 1) % M;
dp[i][j][1] += 1ll * dp[i - 1][j + 1][1] * (j + 1) % M;
dp[i][j][0] %= M;
dp[i][j][1] %= M;
if(j) {
dp[i][j][0] += 1ll * dp[i - 1][j - 1][0] * max(0, 2 * n - i - j + 2 + 0) % M;
dp[i][j][1] += 1ll * dp[i - 1][j - 1][1] * max(0, 2 * n - i - j + 2 + 1) % M;
dp[i][j][0] %= M;
dp[i][j][1] %= M;
}
}
}
cout << dp[2 * n + 1][0][1] * qpow(fact[2 * n + 1], M - 2, M) % M * l % M << endl;
}