博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[CODEVS 3037] 线段覆盖 5
阅读量:5248 次
发布时间:2019-06-14

本文共 3081 字,大约阅读时间需要 10 分钟。

描述

数轴上有n条线段,线段的两端都是整数坐标,坐标范围在0~10^18,每条线段有一个价值,请从n条线段中挑出若干条线段,使得这些线段两两不覆盖(端点可以重合)且线段价值之和最大。


分析

提供两种思路:

  1. 利用离散化. 因为这道题本来就是离散化的例题. 将点排序后依次赋值(1~2n, n为线段的条数), 再通过结构体里的信息将离散化后的点的坐标映射到线段上.

  2. 利用二分法直接DP. 看到题解里有二分两个字, 自己YY出一套二分的做法不过好像和题解里的不一样: 将线段按终点从小到大排序, 考虑线段i, 用 f[i][0] 记录不选 i 的最大权值和, f[i][1] 记录选择 i 的最大权值和. 那么显然有 f[i][0] = max{f[i-1][0], f[i-1][1]}. 然后二分 (upper_bound()) 查找最后一个可以接在 i 前的线段 j, 那么 f[i][1] = max{f[j][0], f[j][1]} + v[i].

    不过尴尬的是第二种方法WA了四个点…而且差了不是一个数量级…


代码

3791ms, 65MB

// 1. 离散化#include 
#include
using namespace std; typedef long long LL;const int maxn = 1000000 + 10;LL f[maxn<<1];struct Line { int s, t, v; bool operator < (const Line& rhs) const { if(t != rhs.t) return t < rhs.t; if(s != rhs.s) return s < rhs.s; return v < rhs.v; }}lines[maxn];struct Point { bool d; // d=0 -> on left; d=1 -> on right LL pos; // previous position int id, x; // id of the line, current position bool operator < (const Point& rhs) const { return pos < rhs.pos; }}points[maxn<<1];int main() { int n; scanf("%d", &n); for(int i = 0; i < n; i++) { LL s, t; scanf("%lld%lld%d", &s, &t, &lines[i].v); points[i<<1] = (Point) {
0, s, i}; points[(i<<1)^1] = (Point) {
1, t, i}; } sort(points, points + 2*n); // discretization int base = 0, cnt = 0; while(base < 2*n) { int cur = base; points[cur++].x = ++cnt; while(points[cur].pos == points[base].pos && cur < 2*n) points[cur++].x = cnt; base = cur; } for(int i = 0; i < 2*n; i++) { Point& P = points[i]; if(P.d == 0) lines[P.id].s = P.x; else lines[P.id].t = P.x; } sort(lines, lines + n); LL ans = 0LL; for(int cur = 0, pre = 0; cur < n; cur++) { Line& L = lines[cur]; if(L.t != pre) { for(int i = pre + 1; i <= L.t; i++) f[i] = f[pre]; pre = L.t; } ans = max(ans, (f[L.t] = max(f[L.t], f[L.s] + L.v))); } printf("%lld\n", ans); return 0;}

// 二分#include 
#include
using namespace std; typedef long long ll;const int maxn = 1000000 + 10;ll f[maxn][2], t[maxn];struct Line { ll s, t, v; bool operator < (const Line& rhs) const { if(t != rhs.t) return t < rhs.t; if(v != rhs.v) return v > rhs.v; return s > rhs.s; }}lines[maxn];int main() { int n; scanf("%d", &n); for(int i = 0; i < n; i++) { ll s, t, v; scanf("%lld%lld%lld", &s, &t, &v); lines[i] = (Line) {s, t, v}; } sort(lines, lines + n); for(int i = 0; i < n; i++) t[i] = lines[i].t; // 用于二分查找 f[0][0] = 0; f[0][1] = lines[0].v; for(int i = 1; i < n; i++) { Line L = lines[i]; f[i][0] = max(f[i-1][0], f[i-1][1]); int j = upper_bound(t, t + n, L.s) - t - 1; if(j >= 0) f[i][1] = max(f[j][0], f[j][1]) + L.v; else f[i][1] = L.v; // 前面没有可以和它拼接的线段 } printf("%d\n", max(f[n-1][0], f[n-1][1])); return 0;}

转载于:https://www.cnblogs.com/wfwbz/p/4312314.html

你可能感兴趣的文章
【原创】Maven安装和配置
查看>>
Linux进程管理
查看>>
关于 自定义字体
查看>>
Octotree Chrome安装与使用方法
查看>>
用CALayer实现下载进度条控件
查看>>
Windows 环境下基于 Redis 的 Celery 任务调度模块的实现
查看>>
可编辑路由—Asp.NET MVC项目编译后,修改路由配置可动态加载
查看>>
UESTC 1330 柱爷与远古法阵【高斯消元】
查看>>
Tomcat修改用户名密码教程
查看>>
模块化概念
查看>>
基本排序
查看>>
前端非对称加密,后端Node.js解密(jsencrypt插件)(不需要密钥转码)
查看>>
list删除、集合遍历删除
查看>>
趣谈Java变量的可见性问题
查看>>
图标字体制作 -- 将SVG制作成图标字体文件,通过引入使用
查看>>
为Eclipse添加C/C++开发工具
查看>>
杭州互联网公司汇总
查看>>
Sublime text3 注册失效解决方法
查看>>
C# 强制关闭当前程序进程(完全Kill掉不留痕迹)
查看>>
ssm框架之将数据库的数据导入导出为excel文件
查看>>