2025年5月4日 贵州省赛M题——递增的鸭鸭

1 分钟阅读时长

发布时间:

题目描述

GZU 的农学院在阅湖养了 n 只鸭子,每只鸭子的肉质都有其对应的鲜美度,第 i 只鸭子的鲜美度是在 \([l_i,r_i]\) 中的任意整数。求这 n 只鸭子的鲜美度单调不减的方案数,对 998244353 取模。

  • 输入:第一行一个整数 n (1≤n≤500);接下来 n 行每行两个整数 \(l_i,r_i (1≤l_i,r_i≤10^9)\)
  • 输出:满足条件的方案数,对 998244353 取模

题解

解法:离散化 + DP + 组合计数

DP 状态:\(dp[j]\) = 前 j 只鸭子的合法方案数。

由于 l 和 r 的取值范围较大(1e9),使用离散化缩小到 1e3。

核心思路:假设这 n 个数的范围相等,都是 [l,r],那么方案数可以直接用隔板法求出,为 C(n+r-l, n)。

DP 状态转移:遍历所有离散段,在每个段上尝试集中放一段连续的鸭子,使用组合数更新状态。

完整代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD = 998244353;
int main(){
    int n;cin>>n;
    vector<ll> l(n+1),r(n+1),vt;
    for(int i=1;i<=n;i++) cin>>l[i]>>r[i];
    vt.reserve(2*n);
    for(int i=1;i<=n;i++){
        vt.push_back(l[i]);
        vt.push_back(r[i] + 1);
    }
    sort(vt.begin(), vt.end());
    vt.erase(unique(vt.begin(), vt.end()), vt.end());
    int m = vt.size() - 1;
    vector<ll> len(m);
    for(int j = 0; j < m; j++)
        len[j] = vt[j+1] - vt[j];
    vector<int> L(n+1),R(n+1);
    for(int i = 1; i <= n; i++){
        int Li = lower_bound(vt.begin(), vt.end(), l[i]) - vt.begin();
        int Ri = lower_bound(vt.begin(), vt.end(), r[i] + 1) - vt.begin() - 1;
        L[i] = Li; R[i] = Ri;
    }
    vector<ll> inv(n+2);
    inv[1] = 1;
    for(int i = 2; i <= n+1; i++)
        inv[i] = (MOD - (MOD/i) * inv[MOD % i] % MOD) % MOD;
    vector<ll> dp(n+1, 0), dpnext;
    dp[0] = 1;
    for(int s = 0; s < m; s++){
        vector<ll> f(n+1, 0);
        f[0] = 1;
        if(n >= 1) f[1] = len[s] % MOD;
        for(int t = 2; t <= n; t++){
            ll mul = (len[s] + t - 1) % MOD;
            f[t] = f[t-1] * mul % MOD * inv[t] % MOD;
        }
        dpnext = dp;
        for(int j = 0; j <= n; j++){
            if(dp[j] == 0) continue;
            if(j == n) continue;
            if(!(L[j+1] <= s && s <= R[j+1])) continue;
            for(int t = 1; j + t <= n; t++){
                int duckPos = j + t;
                if(!(L[duckPos] <= s && s <= R[duckPos])) break;
                dpnext[j+t] = (dpnext[j+t] + dp[j] * f[t]) % MOD;
            }
        }
        dp.swap(dpnext);
    }
    cout << dp[n] % MOD << "\n";
    return 0;
}

发表评论