補題記錄:2021牛客多校第二場題解
阿新 • • 發佈:2021-08-25
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; }