补题记录:2021牛客多校第二场题解

2021牛客多校第二场G:League of Legends 题解

题意

给你n个区间,将这些区间分成k组,使得每组内的任意俩区间都有交集,求总的最大交集。

思路

首先我们考虑大区间包含小区间的情况,当一个大区间包含小区间的时候,对于大区间,我们可以将其单独放在一个区间。这样能保证收益最大。剩下的我们可以排序,根据左区间来进行dp

dp表示:dp[i][j]表示前i个区间分成j组的最大收益

dp转移:dp[i][j]=max(dp[k1][j1]+R[k]L[i])(R[k]>L[i],1ki)

直接做的话,时间复杂度是n3的,但是我们注意到,可以将dp[k1][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;
}
posted @   Time_Limit_Exceeded  阅读(35)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示