http://codeforces.com/gym/101341/problem/K

题意:给出n个区间,每个区间有一个l, r, w,代表区间左端点右端点和区间的权值,现在可以选取一些区间,要求选择的区间不相交,问最大的权和可以是多少,如果权和相同,则选区间长度最短的。要要求输出区间个数和选了哪些区间。

思路:把区间按照右端点排序后,就可以维护从左往右,到p[i].r这个点的时候,已经选择的最大权和是多少,最小长度是多少,区间个数是多少。

因为可以二分找右端点小于等于当前区间的左端点的某个区间(index),然后就有

dp[i] = max(dp[index] + w[index], dp[i]).

这题的我觉得困难的是打印使用了哪些区间,一开始想的方法超时了。

因为用pre数组记录路径,但是路径只是代表当前的解从哪里更新过来的,而不能记录是由哪一个点推出新的最优解。

一开始我用了一个bool型的vis数组判断是否在第i个点更新的答案,然后每次往前找,这样最坏会达到O(n^2)。

但是这样肯定扫了很多重复的情况,因此还可以用递推来构造vis数组,代表当前这个解最后使用了哪一个区间推出来。pre数组也使用递推的形式。

每次如果更新的了,就vis[i] = i,pre[i] = index,否则就vis[i] = vis[i-1], pre[i] = pre[i-1]。

 #include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define N 200010
#define INF 0x3f3f3f3f
struct node {
int l, r, w, id;
bool operator < (const node &rhs) const {
if(r != rhs.r) return r < rhs.r;
return l < rhs.l;
}
} p[N];
LL dp[N], len[N];
int tol[N], pre[N], vis[N];
vector<int> ans;
// vis表示新的DP答案由哪个推出来的
// pre表示当前这个点可以由哪一个点跳过来
// dp[i]表示到第i个右端点的时候最大权和
// len[i]表示到第i个右端点的时候最小长度
// tol[i]表示区间个数 int main() {
int n; scanf("%d", &n);
for(int i = ; i <= n; i++) scanf("%d%d%d", &p[i].l, &p[i].r, &p[i].w), p[i].id = i;
sort(p + , p + + n);
for(int i = ; i <= n; i++) {
dp[i] = dp[i-], len[i] = len[i-], tol[i] = tol[i-], pre[i] = pre[i-], vis[i] = vis[i-];
node now = (node) { INF, p[i].l, , };
int index = upper_bound(p + , p + n + , now) - p - ;
// while(!vis[index] && index) index--;
if(dp[index] + p[i].w > dp[i]) {
dp[i] = dp[index] + p[i].w;
len[i] = len[index] + p[i].r - p[i].l;
tol[i] = tol[index] + ;
pre[i] = index; vis[i] = i;
} else if(dp[index] + p[i].w == dp[i] && len[index] + p[i].r - p[i].l < len[i]) {
len[i] = len[index] + p[i].r - p[i].l;
tol[i] = tol[index] + ;
pre[i] = index; vis[i] = i;
}
// printf("index : %d %d %d %d %lld\n", p[i].id, p[vis[i]].id, p[index].id, p[pre[i]].id, dp[i]);
}
int ed = n;
while(ed) { ans.push_back(p[vis[ed]].id); ed = pre[ed]; }
sort(ans.begin(), ans.end());
printf("%d %lld %lld\n", tol[n], dp[n], len[n]);
for(int i = ; i < ans.size(); i++) printf("%d%c", ans[i], i + == ans.size() ? '\n' : ' ');
return ;
}

最新文章

  1. js 的一些知识 摘自http://img0.pconline.com.cn/Pc_intranet/1105/13/313647_7.pdf
  2. 框架Spring笔记系列 一 基础
  3. 了解linux下RAID(磁盘阵列)创建和管理
  4. sql中的行转列和列转行的问题
  5. OSPF理解
  6. exp函数
  7. JavaScript 中怎样判断文本框只能输出英文字母、汉字和数字,不能输入特殊字符!
  8. jquery ajax GET POST 跨域请求实现
  9. Fckeditor漏洞利用总结
  10. IAR中 C语言位定义
  11. StarUML启动报RPC服务器不可用错误
  12. 树(最小乘积生成树,克鲁斯卡尔算法):BOI timeismoney
  13. 解决 SQLSERVER 2008 无法删除作业
  14. vs2013调试的时候卡顿
  15. Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析
  16. SqLiter
  17. 201521123090《JAVA程序设计》第二周学习总结
  18. Django中多表查询思路
  19. Android:谈一谈安卓应用中的Toast情节(基础)
  20. 验证性控件的使用--验证两个文本框至少有一个不为空CustomValidator

热门文章

  1. Matlab随笔之线性规划
  2. 深度分析WM_PAINT和WM_ERASEBKGND消息
  3. 模拟QQ窗口抖动效果(通过MoveWindow和Sleep进行模拟)
  4. ELINK离线编程器版本说明
  5. 照片美妆---基于Haar特征的Adaboost级联人脸检测分类器
  6. Windows 10开发基础——启动默认应用的URI
  7. UWP中String 转为Path Data
  8. QT 那些事
  9. Tomcat cache 缓存 编译
  10. SpringMVC使用MultipartFile文件上传,多文件上传,带参数上传