CF1153F - Serval and Bonus Problem(概率dp)
阿新 • • 發佈:2021-09-17
題意
有一段長為\(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\)
設\(dp[i][j][x]\)代表已經選擇了\(i\)個點,未選點中有\(j\)個點未和前\(i\)個點匹配(即已經有\(\frac{i-j}{2}\)對區間配對好了),其中\(x=\{0,1\}\),代表點\(x\)已經被選過了。
轉移(當前在\(i\)):
- 如果\(j \ge k\),那麼當前位置可以放\(x\),這樣\(x\)就被大於等於\(k\)的區間包含了。
- 當前位置放的是未匹配點,未匹配點就少1,這樣的點有\(j+1\)個。
- 當前位置放的不是未匹配的點,會導致未匹配點多1。這樣點有\(2n-(i-1)-(j-1)+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; }