1. 程式人生 > 其它 >補題記錄:2021牛客多校第二場題解

補題記錄:2021牛客多校第二場題解

2021牛客多校第二場G:League of Legends 題解

題意

給你\(n\)個區間,將這些區間分成\(k\)組,使得每組內的任意倆區間都有交集,求總的最大交集。

思路

首先我們考慮大區間包含小區間的情況,當一個大區間包含小區間的時候,對於大區間,我們可以將其單獨放在一個區間。這樣能保證收益最大。剩下的我們可以排序,根據左區間來進行\(dp\)

\(dp\)表示:\(dp[i][j]\)表示前\(i\)個區間分成\(j\)組的最大收益

\(dp\)轉移:\(dp[i][j] = max(dp[k - 1][j - 1] + R[k] - L[i]) (R[k] > L[i], 1 \le k \le i)\)

直接做的話,時間複雜度是\(n^3\)的,但是我們注意到,可以將\(dp[k - 1][j] + R[k]\)這部分看作一個整體,維護一個單調佇列即可

#include <bits/stdc++.h>
#define endl '\n'
#define ls u << 1
#define rs u << 1 | 1
#define x first
#define y second
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL,LL> PLL;
const int INF = 0x3f3f3f3f, N = 5050;
const int MOD = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1);
inline int lowbit(int x) {return x & (-x);}
int dp[N][N], q[N], hh, tt;
int pre[N], re[N];
inline void solve() {
    int n, k; cin >> n >> k;
    vector<PII> p(n + 1), a(n + 1);
    int c1 = 0, c2 = 0;
    for (int i = 1; i <= n; i ++ ) cin >> p[i].x >> p[i].y;
    sort(p.begin() + 1, p.end());
    //開始處理大區間
    int mxr = INF;
    for (int i = n; i; i -- ) {
        if (p[i].y < mxr) {
            mxr = p[i].y;
            a[++ c1] = p[i];
        } else re[++ c2] = p[i].y - p[i].x;
    }
    sort(a.begin() + 1, a.begin() + 1 + c1);
    memset(dp, -0x3f, sizeof dp);
    dp[0][0] = 0;
    for (int j = 1; j <= k; j ++ ) {
        hh = 1, tt = 0;
        for (int i = 1; i <= c1; i ++ ) {
            while (hh <= tt && a[q[hh]].y <= a[i].x) hh ++;//注意這裡,我們一般的彈出隊頭都是if,這裡是因為有多個隊頭未滿足才彈出多個
            while (hh <= tt && dp[q[tt] - 1][j - 1] + a[q[tt]].y <= dp[i - 1][j - 1] + a[i].y) tt --;
            q[++ tt] = i;
            dp[i][j] = dp[q[hh] - 1][j - 1] + a[q[hh]].y - a[i].x;
        }
    }
    //最後單獨處理大區間,分別單獨成組,記錄最大值即可
    sort(re + 1, re + 1 + c2, greater<int>());
    for (int i = 1; i <= c2; i ++ ) pre[i] = pre[i - 1] + re[i];
    int res = 0;
    for (int i = 0; i <= c2; i ++ ) {
        if (k < i) break;
        res = max(res, dp[c1][k - i] + pre[i]);
    }
    cout << res << endl;
}
int main() {
#ifdef DEBUG
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    auto now = clock();
#endif
    ios::sync_with_stdio(false), cin.tie(nullptr);
    cout << fixed << setprecision(2);
//    int T; cin >> T;
//    while (T -- )
        solve();
#ifdef DEBUG
    cout << "============================" << endl;
    cout << "Program run for " << (clock() - now) / (double)CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif
    return 0;
}