NOIP2023模拟2联测23 C. 负责

NOIP2023模拟2联测23 C. 负责

题目大意

给你 n 个区间 [li,ri] ,每个区间有个 wi 。如果两个区间有交集(包括端点)那么两个区间就可以连边,形成一个图。

现在需要你删除一些区间,使得每个区间大小不超过 k 。问最小删除的区间权值和。

思路

显然,想要断开一个连通块,那就是要把包含某个点的区间全部删掉。

dpi 表示只考虑在 ri 之前的区间,且 ri 是最后一个断开的地方的最大选的区间的权值和。

每次向后更新时加上区间的权值,如果区间个数大于 k 就把权值最小的区间删掉,用一个堆维护。

时间复杂度 O(n2log2n)

code

#include <bits/stdc++.h>
#define fu(x , y , z) for(int x = y ; x <= z ; x ++)
#define LL long long
using namespace std;
const int N = 2505;
int n , k , b[N] , f[N];
LL sum , ans , dp[N];
struct Re {
    int l , r;
    LL w;
} re[N];
priority_queue<LL , vector<LL> , greater<LL>> q;
bool cmp (Re x , Re y) { return x.r != y.r ? x.r < y.r : x.l < y.l; }
int main () {
    scanf ("%d%d" , &n , &k);
    fu (i , 1 , n) {
        scanf ("%d%d%lld" , &re[i].l , &re[i].r , &re[i].w);
        sum += re[i].w;
    }
    sort (re + 1 , re + n + 1 , cmp);
    LL now;
    fu (i , 0 , n) {
        ans = max (ans , dp[i]);
        now = 0;
        while (!q.empty ())
            q.pop ();
        fu (j , i + 1 , n) {
            if (re[i].r < re[j].l) {
                now += re[j].w;
                q.push (re[j].w);
                if (q.size () > k) {
                    now -= q.top ();
                    q.pop ();
                }
            }
            dp[j] = max (dp[j] , ans + now);
        }
    }
    printf ("%lld" , sum - ans);
    return 0;
}
posted @   2020fengziyang  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
点击右上角即可分享
微信分享提示