洛谷 P4182

首先把所有线段按左端点升序,左端点相同按右端点升序排序。发现如果一个线段完全被另一个线段包含,那把它去掉也没有影响。于是我们先去掉这种线段,然后进行 DP 。设 fi,j 表示前 i 个区间删去 j 个,且钦定第 i 个区间不删除的最大覆盖点数。那么 fi,j=maxk<i(fk,j(ik1)+rimax(li,rk)) 。简单解释一下,就是钦定上一个选的是 k(k,i) 间的全都不选。因为 ik1K ,所以复杂度为 O(nK2)
对于 k 比较小,即 rk<li 时的情况,fi,j=max(fk,j(ik1)+rili)。如果我们能对于每一个 ij1 预处理出 fk,k(ij1) 的最大值 p ,就可以 O(1) 转移了。
对于 k 比较大,即 rk>li 时的情况,fi,j=max(fk,j(ik1)+rirk)。我们用单调队列维护 fk,j(ik1)rk 的最大值。当单调队列中的元素不满足 rk>li 时就弹出,弹出的时候顺便处理出 p
总结一下,我们需要处理出 rk<lifk,k(ij1) 的最大值,再开 n 个单调队列,第 ij 个单调队列维护 fi,jri 的最大值。这样复杂度就降为了 O(nK)

Code:

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
typedef pair <int, int> pii;
const int N = 100005, M = 105;
int n, k;
pii a[N], b[N];
int f[N][M], p[N];
deque <int> q[N];

int main() {
	scanf("%d%d", &n, &k);
	for (int i = 1; i <= n; ++i) scanf("%d%d", &a[i].fi, &a[i].se);
	if (k >= n) return printf("%d", 0), 0;
	sort(a + 1, a + n + 1, [](pii x, pii y) {
		return x.fi != y.fi ? x.fi < y.fi : x.se < y.se;
	});
	int mx = -1, tot = 0;
	for (int i = 1; i <= n; ++i) {
		if (a[i].se > mx) b[++tot] = a[i];
		else --k;
		mx = max(mx, a[i].se);
	}
	k = max(k, 0), b[++tot] = pii(1e9, 1e9);
	for (int i = 1; i <= tot; ++i)
		for (int j = 0; j <= min(i - 1, k); ++j) {
			int t = i - j - 1;
			while (q[t].size() && b[q[t].front()].se < b[i].fi) {
				p[t] = max(p[t], f[q[t].front()][q[t].front() - t]);
				q[t].pop_front();
			}
			f[i][j] = max(f[i][j], p[t] + b[i].se - b[i].fi);
			if (q[t].size()) f[i][j] = max(f[i][j], f[q[t].front()][q[t].front() - t] + b[i].se - b[q[t].front()].se);
			t = i - j;
			while (q[t].size() && f[q[t].back()][q[t].back() - t] - b[q[t].back()].se <= f[i][j] - b[i].se) q[t].pop_back();
			q[t].push_back(i);
		}
	printf("%d", f[tot][k]);
	return 0;
}
posted @   Kobe303  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示