• CF1295F


    题目

    (a_i)在范围([l_i, r_i])等概率取值,求序列({a_i})非递增的概率。(nle 50)(l_ile r_i le 998244351)

    题解

    即求序列非递增的方案数。

    由于区间范围非常大,而区间数又很少。因此可以离散化端点,给区间分段。这样分下来总段数就是(O(n))级别了。可以使用dp解决。

    这样每个大区间,每分成若干个连续的右闭左开的小区间,以及最后一个左闭右闭仅仅包含一个数的小区间。

    (dp[i][j])代表前(i)个区间,当前在第(j)个小区间的方案数。转移很好想,关键在于求解一个区间内(k)个非递增位置的方案数。这个用差分的方法,转化为差值大于等于0,差值求和小于等于区间长度,可以用隔板法解决。

    注意最后左闭右闭小区间的处理即可。

    #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 = 1e2 + 10;
    const int MX = 1e5 + 10;
    const int M = 998244353;
    const double eps = 1e-5;
    
    ll dp[N][N];
    ll rfact[MX];
    typedef pair<int, int> PII;
    PII segs[N];
    vector<int> num;
    
    
    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;
    	rfact[0] = 1;
    	for(int i = 1; i < MX; i++) {
    		rfact[i] = rfact[i - 1] * qpow(i, M - 2, M) % M;
    	}
    	num.push_back(0);
    	int n;
    	cin >> n;
    	ll tot = 1;
    	for(int i = 1; i <= n; i++) {
    		int l, r;
    		cin >> l >> r;
    		tot = (r - l + 1) * tot % M;
    		segs[i] = {l, r};
    		num.push_back(l);
    		num.push_back(r);
    	}
    	sort(num.begin(), num.end());
    	num.erase(unique(num.begin(), num.end()), num.end());
    	for(int i = 1; i <= n; i++) {
    		segs[i].first = lower_bound(num.begin(), num.end(), segs[i].first) - num.begin();
    		segs[i].second = lower_bound(num.begin(), num.end(), segs[i].second) - num.begin();
    	}
    	for(int i = 0; i < N; i++) dp[0][i] = 1;
    	for(int i = 1; i <= n; i++) {
    		int l = segs[i].first, r = segs[i].second;
    		for(int j = r; j >= l; j--) {
    			int rg;
    			if(j - 1 >= l) rg = num[j] - num[j - 1];
    			else rg = 1;
    			ll pw = rg;
    			for(int k = i - 1; k >= 0; k--) {
    
    				if(k && segs[k].first == j) 
    					dp[i][j] = (dp[i][j] + dp[k][j] % M * pw % M * rfact[i - k] % M) % M;
    				else
    					dp[i][j] = (dp[i][j] + dp[k][j + 1] % M * pw % M * rfact[i - k] % M) % M;
    				pw = pw * (rg + i - k) % M;
    				if(!(segs[k].second >= j && segs[k].first < j)) break;
    			}
    			dp[i][j] = (dp[i][j] + dp[i][j + 1]) % M;
    		}
    		for(int j = l - 1; j >= 0; j--) {
    			dp[i][j] = dp[i][j + 1];
    		}
    	}
    	cout << dp[n][0] * qpow(tot, M - 2, M) % M << endl;
    }
    
  • 相关阅读:
    通用测试用例(二)
    loadrunner基础学习笔记八-分析场景
    loadrunner基础学习笔记七-面向目标场景
    Detect the Virus ZOJ
    考研路茫茫——单词情结 HDU
    DNA Sequence POJ
    病毒侵袭持续中 HDU
    病毒侵袭 HDU
    Keywords Search HDU
    codeforces 949B :A Leapfrog in the Array 找规律
  • 原文地址:https://www.cnblogs.com/limil/p/15267773.html
Copyright © 2020-2023  润新知