Codeforces Round #672 (Div. 2) D. Rescue Nibel!(排序)

题目链接:https://codeforces.com/contest/1420/problem/D

前言

之前写过这场比赛的题解,不过感觉这一题还可以再单独拿出来好好捋一下思路。

题意

给出 $n$ 个闭区间,问 $k$ 个区间共区间共有多少种情况。

题解一

以区间为单位进行考虑,排序+优先队列。

将所有区间以左端点为第一关键字,右端点为第二关键字从小到大排序,优先队列中存储不小于当前区间左端点的之前区间的右端点,每个区间对答案的贡献即 $C_{(pque.size(), k - 1)}$ 。

代码

#include <bits/stdc++.h>
using namespace std;
constexpr int N = 1e6 + 100;
constexpr int MOD = 998244353;

int fac[N], inv[N];

int binpow(int a, int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = 1LL * res * a % MOD;
        a = 1LL * a * a % MOD;
        b >>= 1;
    }
    return res;
}

long long C(int n, int m){
    if(m < 0 or m > n) return 0;
    return 1LL * fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}

void Init(){
    fac[0] = 1;
    for (int i = 1; i < N; i++) fac[i] = 1LL * fac[i - 1] * i % MOD;
    inv[N - 1] = binpow(fac[N - 1], MOD - 2);
    for (int i = N - 2; i >= 0; i--) inv[i] = 1LL * inv[i + 1] * (i + 1) % MOD;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    Init();
    
    int n, k;
    cin >> n >> k;
    
    vector<pair<int, int>> seg(n);
    for (auto &[l, r] : seg) cin >> l >> r;
        
    sort(seg.begin(), seg.end());
    
    long long ans = 0;
    
    priority_queue<int, vector<int>, greater<int>> pque;
    
    for (int i = 0; i < n; i++) {
        auto [l, r] = seg[i];
        while (pque.size() and pque.top() < l) pque.pop();
        ans += C(pque.size(), k - 1);
        ans %= MOD;
        pque.push(r);
    }
    
    cout << ans << "
";
    
    return 0;
}

题解二

以点为单位进行考虑,排序+离散化+差分。

记录包含当前点 $i$ 的区间个数 $dif_i$ 和以当前点为左端点的区间个数 $bg_i$,将 $k$ 个区间视为两部分,从之前区间选出的部分和从以当前点为左端点的区间中选出的部分,即 $C_{(dif_i - bg_i, k-j)} imes C_{(bg_i, j)}$,为了去重 $j$ 的值从 $1$ 取起,值域为 $[1,min(k, bg_i)]$,每个点对答案的贡献为 $sum_{j = 1}^{min(k, bg_i)} limits C_{(dif_i - bg_i, k-j)} imes C_{(bg_i, j)}$ 。

代码

#include <bits/stdc++.h>
using namespace std;
constexpr int N = 1e6 + 100;
constexpr int MOD = 998244353;

int fac[N], inv[N];

int binpow(int a, int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = 1LL * res * a % MOD;
        a = 1LL * a * a % MOD;
        b >>= 1;
    }
    return res;
}

long long C(int n, int m){
    if(m < 0 or m > n) return 0;
    return 1LL * fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}

void Init(){
    fac[0] = 1;
    for (int i = 1; i < N; i++) fac[i] = 1LL * fac[i - 1] * i % MOD;
    inv[N - 1] = binpow(fac[N - 1], MOD - 2);
    for (int i = N - 2; i >= 0; i--) inv[i] = 1LL * inv[i + 1] * (i + 1) % MOD;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    Init();
    
    int n, k;
    cin >> n >> k;
    
    vector<int> x(n), y(n);
    vector<int> disc;
    for (int i = 0; i < n; i++) {
        cin >> x[i] >> y[i];
        disc.push_back(x[i]);
        disc.push_back(y[i]);
    }

    sort(disc.begin(), disc.end());
    disc.resize(unique(disc.begin(), disc.end()) - disc.begin());
    
    vector<int> dif(disc.size() + 1), bg(disc.size() + 1);
    for (int i = 0; i < n; i++) {
        int l = lower_bound(disc.begin(), disc.end(), x[i]) - disc.begin();
        int r = lower_bound(disc.begin(), disc.end(), y[i]) - disc.begin();
        ++bg[l];
        ++dif[l];
        --dif[r + 1];
    }
    
    long long ans = 0;
    for (int i = 0; i < int(dif.size()); i++) {
        if (i > 0) dif[i] += dif[i - 1];
        for (int j = 1; j <= min(k, bg[i]); j++) {
            ans += C(dif[i] - bg[i], k - j) * C(bg[i], j);
            ans %= MOD;
        }
    }
    cout << ans << "
";
    
    return 0;
}
原文地址:https://www.cnblogs.com/Kanoon/p/13775659.html