CF1295F Good Contest(概率+组合数学+dp)

41 篇文章 1 订阅
6 篇文章 0 订阅

题目大意:

a i a_i ai [ l i , r i ] [l_i,r_i] [li,ri]等概率选择一个整数,询问 { a n } \{a_n\} {an}非递增的概率

解题思路(思路来源:crashed):

首先能够得到一个非常暴力的 d p dp dp方程: d p [ i ] [ j ] = ∑ k = m a x ( j , l i − 1 ) r i − 1 d p [ i − 1 ] [ k ] dp[i][j]=\sum_{k=max(j,l_{i-1})}^{r_{i-1}}dp[i-1][k] dp[i][j]=k=max(j,li1)ri1dp[i1][k] d p [ i ] [ j ] dp[i][j] dp[i][j]代表第 i i i个数在区间范围内选择 j j j的前 i i i个数的合理方案数
很显而易见,这个方程再怎么优化都会超时,所以不是这样子。

接下来先看该题目的一个子问题:一个大小为 m m m的区间内选择 n n n个数非递增的方案数:

  • 大小为 m m m的区间可以看成 m m m个不同的桶,现在问题就转换成, n n n个一样的球放进 m m m个不同桶内的方案数,根据插空法,方案数为: C n + m − 1 m − 1   o r   C n + m − 1 n C_{n+m-1}^{m-1} \ or \ C_{n+m-1}^{n} Cn+m1m1 or Cn+m1n

接下来是原问题的解析:

  • 对于这类区间很大的问题,可以先试着将其进行离散化以及把闭区间转换为开区间
  • 原区间: [ L i , R i ) [L_i,R_i) [Li,Ri),离散化后为: [ l i . r i ) [l_i.r_i) [li.ri),且因为离散化后 [ l i , l i + 1 ) , [ l i + 1 , l i + 2 ) . . . [ r i − 1 , r i ) [l_i,l_i+1),[l_i+1,l_i+2)...[r_i-1,r_i) [li,li+1)[li+1,li+2)...[ri1,ri)分别对应原来的一个大区间
  • d p [ i ] [ j ] dp[i][j] dp[i][j]为前 i i i个数且第 i i i个数在离散化后的 [ j , j + 1 ) [j,j+1) [j,j+1)(对应未离散化的一个大区间, j ∈ [ l i , r i ) j\in[l_i,r_i) j[li,ri))区间内的方案数
  • 所以可以枚举连续有多少个数(从 i i i往前)同时出现 [ j , j + 1 ) [j,j+1) [j,j+1)来推导 d p dp dp方程 d p [ i ] [ j ] = ∑ k = 1 i [ ∀ :   k ≤ p ≤ i , [ j , j + 1 ) ∈ [ l k , r k ) ] ∑ t ( t > j ) d p [ k − 1 ] [ t ] ⋅ C L + i − k i − k + 1 dp[i][j]=\sum_{k=1}^{i}[\forall: \ k\le p \le i, [j,j+1) \in[l_k,r_k)]\sum_{t(t>j)}dp[k-1][t]\cdot C_{L+i-k}^{i-k+1} dp[i][j]=k=1i[: kpi,[j,j+1)[lk,rk)]t(t>j)dp[k1][t]CL+ikik+1 L L L [ j , j + 1 ) [j,j+1) [j,j+1)对应的原来区间长度
  • 因为 L L L可能很大,所以组合数要 O ( n ) O(n) O(n)算,后半部分的 ∑ t ( t > j ) d p [ k − 1 ] [ t ] \sum_{t(t>j)}dp[k-1][t] t(t>j)dp[k1][t]可以通过后缀和优化,所以总复杂度是 O ( n 4 ) O(n^4) O(n4)

AC代码:

#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) //不能跟puts混用
#define seteps(N) fixed << setprecision(N)
#define endl "\n"
const int maxn = 55;
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
const ll mod = 998244353;
ll qpow(ll a, ll b) {
   ll res = 1;
   while (b) {
	   if (b & 1) res = res * a % mod;
	   a = a * a % mod;
	   b >>= 1;
   }
   return res;
}
ll C(ll n, ll m) {
    if (n < m) return 0;
    ll res = 1;
    for (int i = 1; i <= m; i++) res = res * (n - i + 1) % mod * qpow(i, mod - 2) % mod;
    return res;
}
int n, l[maxn], r[maxn];
int lef[maxn], rig[maxn];
int p[maxn << 1], cntp;
ll dp[maxn][maxn << 1];
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> l[i] >> r[i], r[i] += 1, p[++cntp] = l[i], p[++cntp] = r[i];
    sort (p + 1, p + cntp + 1);
    cntp = unique(p + 1, p + cntp + 1) - (p + 1);
    for (int i = 1; i <= n; i++) lef[i] = lower_bound(p + 1, p + cntp + 1, l[i]) - p, rig[i] = lower_bound(p + 1, p + cntp + 1, r[i]) - p;
    for (int i = 1; i <= cntp; i++) dp[0][i] = 1;
    lef[0] = 1, rig[0] = cntp + 1;
    for (int i = 1; i <= n; i++) {
        for (int j = lef[i]; j < rig[i]; j++) {
            int L = p[j + 1] - p[j];
            for (int k = i; k; k--) {
                if (!(lef[k] <= j && j + 1 <= rig[k])) break;
                dp[i][j] = (dp[i][j] + dp[k - 1][j + 1] * C(L + i - k, i - k + 1) % mod) % mod;
            }
        }
        for (int j = cntp - 1; j; j--)
            dp[i][j] = (dp[i][j + 1] + dp[i][j]) % mod;
    }
    ll ans = dp[n][1];
    for (int i = 1; i <= n; i++)
        ans = ans * qpow(r[i] - l[i], mod - 2) % mod;
    cout << ans << endl;
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值