zoukankan      html  css  js  c++  java
  • CF1153F

    题意

    有一段长为(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] o dp[i][j][1] ]

    • 当前位置放的是未匹配点,未匹配点就少1,这样的点有(j+1)个。

    [(j+1)cdot dp[i-1][j+1][x] o 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] o 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 '
    '
    #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;
    }
    
  • 相关阅读:
    Haskell Types与Typeclasses
    Haskell Tuple相关总结
    Haskell List相关操作
    Emacs 常用快捷键
    Emacs 参考资料
    Haskell Platform (windows)
    生成zip压缩包
    递归复制一个文件
    写表格
    读表格
  • 原文地址:https://www.cnblogs.com/limil/p/15305586.html
Copyright © 2011-2022 走看看