归纳题目的性质

每一个加速器效果相同(1)

车子等到所有人上车之后才会发车, 这个最早发车时间不由加速器的配比决定(2)

要优化的对象: "所有人搭车时间总和". (3)

算法

根据性质(2), 我们可以预处理出这个"最早发车时间", 记为\(start_i\)

60分

根据(2), (3)设计算法, 想到DP.

令站点i, 使用加速器个数为j的最晚发车时间为\(dp_{i, j}\)(蕴含性质1), 则可以由\(dp_{i, j} \rightarrow dp_{i+1, k}(k>j)\), 其中贡献可以预处理(思考性质3)

复杂度\(O(nk^2)\)

100分

思考贪心: 把整个列车系统看成一个整体(前一个算法是把每一站分拆), 将每个加速器的贡献拆开. (性质1)

思考加速器的性质 : 在每一站使用都相同(令其为性质4), 考虑枚举在当前状态下哪一站加速最佳.(在\(O(n)\)内)

定义如下符号:

\[rb_i: 加速器设在第i站的影响范围(先不解释)\\
tim_i: 在当前状态下, 汽车到达i站最佳时间\\
l_i: i\rightarrow i+1 时间
\]

这个算法的关键是\(rb_i\)数组, 请看定义, 不理解没关系

\[rb_i = i+1\ \text{if not ok_to_opt}\\
\text{else } rb_i = rb_{i+1}
\]

如果在第i站至i+1站的路程中使用加速器, 目的地\(\in[i+1,rb_i]\) 的人这些人消耗时间会-1s:

为什么?

把目的地\(\in[i+1,rb_i]\) 的人分为2类:

  1. 出发地\(\leq\)i.
  2. 出发地\(>\)i

第1类人显然消耗时间会减少1s

第2类人虽然在\(i\rightarrow i+1\)的路程中没有减少消耗时间, 但是由于发车时间提前了1s(根据\(rb_i\)的定义), 他们消耗时间也会减少1s (这个我一开始没有想到)....

而那些目的地\(>rb_i\)的人来说, 发车时间太晚, \(tim_{rb_{i+1}}\)的减小无济于事...

经过k次迭代我们就做完啦(滑稽)

complexity \(O(nk)\), it's unexpected but it works(and also fast)!

code

#include<bits/stdc++.h>
using namespace std; int read() {
int f = 1, ans = 0; char c = getchar();
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0', c = getchar();}
return ans * f;
}
#define rep(i, _st, _ed) for(register int i = (_st); i <= (_ed); ++i)
const int maxm = 10005, maxn = 1005, maxk = 1e5+5;
int leave[maxn], dis[maxn], endp[maxn], rg[maxn], t[maxn]; //range是关键字
int st[maxm], ed[maxm], arri[maxm];
int n, m, k, ans; void test() { int tmp = read(); printf("%d\n", tmp);}
void put(int x) {printf("%d\n", x);}
signed main(){
// while(1)test();
scanf("%d %d %d", &n, &m, &k);
rep(i, 1, n-1) dis[i] = read();
rep(i, 1, m) arri[i] = read(), st[i] = read(), ed[i] = read();
rep(i, 1, m) {
leave[st[i]] = max(leave[st[i]], arri[i]);
endp[ed[i]]++;
}
rep(i, 2, n) endp[i] += endp[i-1]; // endp[i] is prefix sum
ans = 0;
rep(i, 1, n) t[i] = max(leave[i-1], t[i-1]) + dis[i-1]; //, put(t[i]);
rep(i, 1, m) ans = ans + t[ed[i]] - arri[i];
//errorcode : ans = ans + t[ed[i]] - t[st[i]];
//一些预处理工作
// put(ans);
while(k--){
rg[n] = n;
for(int i = n-1; i >= 1; --i) {
if(t[i+1] > leave[i+1]) rg[i] = rg[i+1];
else rg[i] = i + 1;
// put(rg[i]);
}
// put(0);
int opt = 0, pos = 0;
rep(i, 1, n-1) {
if(dis[i] > 0 && endp[rg[i]] - endp[i] > opt) {
opt = endp[rg[i]] - endp[i];
pos = i;
}
}
if(pos==0) break;
ans -= opt;
--dis[pos]; //don't forget to update the distance!!
rep(i, pos, n) t[i] = max(leave[i-1], t[i-1]) + dis[i-1];
//don't forget to update the arrival time!!
}
put(ans);
return 0;
}

大家来找茬

这是我的一个错误版本代码, 有5处bug..

#include<bits/stdc++.h>
using namespace std; // #prag\ma G++ optimize("O3") int read() {
int f = 1, ans = 0; char c = getchar();
while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
while(isdigit(c)) {ans = ans * 10 + c - '0', c = getchar();}
return ans * f;
}
#define rep(i, _st, _ed) for(register int i = (_st); i <= (_ed); ++i)
const int maxm = 10005, maxn = 1005, maxk = 1e5+5;
int leave[maxn], dis[maxn], endp[maxn], rg[maxn], t[maxn]; //range是关键字
//t[i]为从第i站出发的时间
int st[maxm], ed[maxm], arri[maxm];
vector<int> d_set[maxn]; //从第i站出发人员集合
int n, m, k, ans;
void test() { int tmp = read(); printf("%d\n", tmp);}
signed main(){
test();
scanf("%d %d %d", &n, &m, &k);
rep(i, 1, n-1) dis[i] = read();
rep(i, 1, m) arri[i] = read(), st[i] = read(), ed[i] = read();
rep(i, 1, m) {
leave[ed[i]] = max(leave[ed[i]], arri[i]);
d_set[st[i]].push_back(ed[i]);
endp[ed[i]]++;
}
ans = 0;
rep(i, 2, n) endp[i] += endp[i-1]; // endp[i] is prefix sum
rep(i, 1, n) t[i] = max(leave[i], t[i-1] + dis[i-1]);
rep(i, 1, m) ans = ans + t[ed[i]] - arri[i];
//errorcode : ans = ans + t[ed[i]] - t[st[i]];
//一些预处理工作 while(k--){
rg[n] = n;
for(int i = n-1; i >= 1; --i)
if(t[i] + dis[i] > leave[i+1]) rg[i] = rg[i+1];
else rg[i] = i + 1;
int opt = 0;
rep(i, 1, n) {
if(dis[i] > 0 && endp[rg[i]] - endp[i] > opt) {
opt = endp[rg[i]] - endp[i];
}
}
ans -= opt;
}
printf("%d\n", ans);
return 0;
}

总结

这道题的结论很优美, 但是优美地不像是可以考试时想出来的...

还是写dp保平安吧...

p.s.这道题对思维缜密性的要求很高

参考: https://blog.csdn.net/qq_37220238/article/details/80059161

https://www.cnblogs.com/pealicx/p/6138785.html(code)

NOIP2011 D2T3 观光公交 做题笔记的更多相关文章

  1. SDOI2016 R1做题笔记

    SDOI2016 R1做题笔记 经过很久很久的时间,shzr终于做完了SDOI2016一轮的题目. 其实没想到竟然是2016年的题目先做完,因为14年的六个题很早就做了四个了,但是后两个有点开不动.. ...

  2. Luogu 1315 【NOIP2011】观光公交 (贪心)

    Luogu 1315 [NOIP2011]观光公交 (贪心) Description 风景迷人的小城Y 市,拥有n 个美丽的景点.由于慕名而来的游客越来越多,Y 市特意安排了一辆观光公交车,为游客提供 ...

  3. C语言程序设计做题笔记之C语言基础知识(下)

    C 语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行 事.并且C是相当灵活的,用于执行计算机程序能完成的 ...

  4. C语言程序设计做题笔记之C语言基础知识(上)

    C语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行事.并且C是相当灵活的,用于执行计算机程序能完成的几乎 ...

  5. SDOI2017 R1做题笔记

    SDOI2017 R1做题笔记 梦想还是要有的,万一哪天就做完了呢? 也就是说现在还没做完. 哈哈哈我竟然做完了-2019.3.29 20:30

  6. SDOI2014 R1做题笔记

    SDOI2014 R1做题笔记 经过很久很久的时间,shzr又做完了SDOI2014一轮的题目. 但是我不想写做题笔记(

  7. LCT做题笔记

    最近几天打算认真复习LCT,毕竟以前只会板子.正好也可以学点新的用法,这里就用来写做题笔记吧.这个分类比较混乱,主要看感觉,不一定对: 维护森林的LCT 就是最普通,最一般那种的LCT啦.这类题目往往 ...

  8. java做题笔记

    java做题笔记 1. 初始化过程是这样的: 1.首先,初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化: 2.然后,初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序 ...

  9. SAM 做题笔记(各种技巧,持续更新,SA)

    SAM 感性瞎扯. 这里是 SAM 做题笔记. 本来是在一篇随笔里面,然后 Latex 太多加载不过来就分成了两篇. 标 * 的是推荐一做的题目. trick 是我总结的技巧. I. P3804 [模 ...

随机推荐

  1. [WC2007]剪刀石头布(最大流)

    洛古 一句话题意:给定一张图,每两点之间有一条有向边或无向边,把所有无向边定向,使图中三元环个数尽量多 因为原图是一个完全图,假设图中任意三点都能构成三元环,那么途中三元环的个数为:\(\binom{ ...

  2. Vue的钩子函数[路由导航守卫、keep-alive、生命周期钩子]

    前言 说到Vue的钩子函数,可能很多人只停留在一些很简单常用的钩子(created,mounted),而且对于里面的区别,什么时候该用什么钩子,并没有仔细的去研究过,且Vue的生命周期在面试中也算是比 ...

  3. 洛谷P1776 宝物筛选

    一道很好的单调队列优化多重背包入门题 令\(v[i]\)表示重量,\(w[i]\)表示价格 ,\(c[i]\)表示最多可放的数量,不难推出朴素的转移方程如下: \(f[i][j]=max\{f[i-1 ...

  4. python的内置模块xml模块方法 xml解析 详解以及使用

    一.XML介绍 xml是实现不同语言或程序直接进行数据交换的协议,跟json差不多,单json使用起来更简单,不过现在还有很多传统公司的接口主要还是xml xml跟html都属于是标签语言 我们主要学 ...

  5. 2018-2019-2 《Java程序设计》第3周学习总结

    20175319 2018-2019-2 <Java程序设计>第3周学习总结 教材学习内容总结 第三周通过课本与蓝墨云上的视频学习了<Java2实用教程>第四章类与对象 成功激 ...

  6. Java Swing实现一个简单而优美的记事本( 较详细注释 )

    Java Swing实现具有基本功能的记事本 目前实现了: 文件 新建 打开 保存 退出前保存询问 编辑 剪切 复制 粘贴 清除 撤销 格式 字体选择 字体颜色选择 帮助 关于 (样式采用了css与h ...

  7. 一、Kubernetes系列之介绍篇

      •Kubernetes介绍 1.背景介绍 云计算飞速发展 - IaaS - PaaS - SaaS Docker技术突飞猛进 - 一次构建,到处运行 - 容器的快速轻量 - 完整的生态环境 2.什 ...

  8. django drf 基础学习4

    0  简介:介绍ModelViewSet基本使用规则1 views引用以及初始化   from rest_framework.viewsets import ModelViewSet     clas ...

  9. POJ 3190

    POJ3190                               摊位预订.时间限制:1000MS内存限制:65536K.共提交材料:12959份接受:4 546名特别法官.描述. 哦,那些 ...

  10. Docker: repository, image, container

    1. 查看image: docker images 2. 查看信息: docker info 3. 搜索image: docker search [image_name], 比如: docker se ...