[SOJ603] 环【贪心】
题意简述:数轴上有\(n\)条线段,将这\(n\)条线段分成恰好\(k\)组,每一组的价值为组内线段的交集长度,求最大总价值。\(1\leq n, k, \leq 6000\)。
对于一条线段\([l_i, r_i]\),如果存在另一条线段\(j\),使得\(l_i\leq l_j, r_i\geq r_j\),则我们称线段\(i\)是“长的”,否则是“短的”。注意若干条线段完全相同时,最后一条线段不能直接认定成“长的”。由定义知,任意两条“短的”线段互不包含。
- Proof:对于任意一条“长的”线段\(i\),它要么与定义它的\(j\)放在同一组,要么单独在一组。
证明:显然将\(i, j\)放在同一组,\(i\)的加入不会使答案变劣。否则,若\(i, j\)不在同一组,且\(i\)与至少一条线段\(k\)在同一组,则将\(i\)从\(k\)所在的组中取出,放入\(j\)所在的组,答案不会变劣。
将左端点排序,用单调栈维护右端点,可以简单求出所有“长的”线段。显然我们只需要对于每一个\(c\in[0, k]\)考虑长度前\(c\)大的“长的”线段和把“短的”线段分成\(k-c\)组时的最大权值即可。
考虑一个初始状态,所有\(m\)条“短的”线段单独分在一个组,边界为\([l_i, r_i]\)。显然每次合并两个组时,一定是合并相邻的两组最优。
若合并当前的第\(i\)组和第\(i+1\)组,设两组交集的左右边界分别为\([x_i, y_i], [x_{i+1}, y_{i+1}]\),则此次合并会导致的权值损失为\(y_{i+1}-x_i\),同时新的边界为\([x_{i+1}, y_i]\)。显然这两组的合并不会对其他组的合并带来的权值变化产生影响,因此贪心去选权值损失最小的一定最优。暴力扫或者用堆实现都可以,复杂度\(O(n^2)\)或\(O(n\log n)\)。
值得注意的是,被合并的两组可能交集为空,在这种情况下,合并可能会导致新的权值为负,而实际的权值显然最低为\(0\)。但是如果有任意一组线段交集为空,则此前提下的最优解一定是选出\(r_i-l_i\)最大的\(k-1\)条线段,其余线段均留在空集中。与之前求出的答案取\(\max\)即可。然而出题人为了卡假做法,根本没有这种数据
// 采用了暴力的实现方式
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cassert>
#include <iostream>
#include <algorithm>
#define R register
#define ll long long
using namespace std;
const int N = 6100, inf = 1e9;
int n, k, numL, numS, nxt[N];
struct node {
int l, r;
inline bool operator < (const node &x) const {
return r - l > x.r - x.l;
}
}seg[N], segL[N], segS[N];
ll sumS[N], ans, sumL;
template <class T> inline void read(T &x) {
x = 0;
char ch = getchar(), w = 0;
while (!isdigit(ch)) w = (ch == '-'), ch = getchar();
while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
x = w ? -x : x;
return;
}
inline bool cmp(const node &a, const node &b) {
return a.l < b.l;
}
int main() {
read(n), read(k);
for (R int i = 1; i <= n; ++i)
read(seg[i].l), read(seg[i].r);
sort(seg + 1, seg + 1 + n);
for (R int i = 1; i < k; ++i)
ans += seg[i].r - seg[i].l;
int lt = 0, rt = inf;
for (R int i = k; i <= n; ++i)
lt = max(lt, seg[i].l), rt = min(rt, seg[i].r);
ans += max(0, rt - lt);
for (R int i = 1; i <= n; ++i) {
int flag = 1;
for (R int j = i + 1; flag && j <= n; ++j)
if (seg[i].l <= seg[j].l && seg[i].r >= seg[j].r)
flag = 0;
if (flag) segS[++numS] = seg[i];
else segL[++numL] = seg[i];
}
sort(segS + 1, segS + 1 + numS, cmp);
for (R int i = 1; i <= numS; ++i)
sumS[numS] += segS[i].r - segS[i].l, nxt[i] = i + 1;
for (R int i = 1; i < numS; ++i) {
int minLos = inf, pos = 0;
for (R int j = 1; nxt[j] <= numS; j = nxt[j]) {
if (segS[nxt[j]].r - segS[j].l < minLos)
pos = j, minLos = segS[nxt[j]].r - segS[j].l;
}
sumS[numS - i] = sumS[numS - i + 1] - minLos;
segS[pos].l = segS[nxt[pos]].l, nxt[pos] = nxt[nxt[pos]];
}
for (R int i = 0; i <= min(numL, k - 1); ++i)
sumL += segL[i].r - segL[i].l, ans = max(ans, sumS[k - i] + sumL);
cout << ans << endl;
return 0;
}
原文地址:https://www.cnblogs.com/suwakow/p/11677547.html
- 遍历文件夹所有文件(示例)
- Visual Studio 2017 : client version 1.22 is too old
- httphandler和httpmodule的区别
- 每周.NET前沿技术文章摘要(2017-06-21)
- Access数据库多表连接查询
- Lucene2.1 的官方示例代码
- 使用NUnit在.Net编程中进行单元测试
- 在CentOS上使用Jexus托管运行 ZKEACMS
- PowerDesigner生成Access数据库
- TechEmpower 13轮测试中的ASP.NET Core性能测试
- 反馈型神经网络
- (Head First 设计模式)学习笔记(1)
- [c#]Webservice中如何实现方法重载(overload)以及如何传送不能序列化的对象作参数
- Web.Config文件配置小记
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 理解Spring中的IoC和DI
- 快速学习-Saturn性能测试报告
- Java源码系列1——ArrayList
- 【Kubernetes】自定义资源CRDs不支持fieldselector
- Cypress系列(48)- and() 命令详解
- Java源码系列2——HashMap
- 快速学习-Saturn Console部署
- MySQL的各种日志
- 本地机器如何访问服务器上的docker容器内的tensorboard?
- MySQL是如何实现可重复读的?
- Java源码系列4——HashMap扩容时究竟对链表和红黑树做了什么?
- 如何理解被 protected 修饰的成员变量?
- 重学数据结构(五、串)
- python boto和boto3操作bucket
- 对比 Redis 中 RDB 和 AOF 持久化