题目描述
风景迷人的小城Y 市,拥有n个美丽的景点。由于慕名而来的游客越来越多, Y市特意安排了一辆观光公交车,为游客提供更便捷的交通服务。观光公交车在第 0分钟出现在 1号景点,随后依次前往2,3,4,…,n 2,3 ,4 ,…,n2,3,4,…,n 号景点。从第i号景点开到第i+1号景点需要Di分钟。任意时刻,公交车只能往前开,或在景点处等待。
设共有m个游客,每位游客需要乘车1次从一个景点到达另一个景点,第i位游客在Ti分钟来到景点 Ai,希望乘车前往景点Bi(Ai<Bi)。为了使所有乘客都能顺利到达目的地,公交车在每站都必须等待需要从该景点出发的所有乘客都上车后才能出发开往下一景点。
假设乘客上下车不需要时间。一个乘客的旅行时间,等于他到达目的地的时刻减去他来到出发地的时刻。因为只有一辆观光车,有时候还要停下来等其他乘客,乘客们纷纷抱怨旅行时间太长了。于是聪明的司机ZZ给公交车安装了k个氮气加速器,每使用一个加速器,可以使其中一个Di−1 。对于同一个Di可以重复使用加速器,但是必须保证使用后Di≥0 。
那么ZZ该如何安排使用加速器,才能使所有乘客的旅行时间总和最小?
输入格式
第1行是3个整数n,m,k每两个整数之间用一个空格隔开。分别表示景点数、乘客数和氮气加速器个数。
第2行是n−1个整数,每两个整数之间用一个空格隔开,第i个数表示从第i个景点开往第i+1个景点所需要的时间,即Dii。
第3行至m+2行每行3个整数 Ti,Ai,Bi每两个整数之间用一个空格隔开。第i+2 行表示第i位乘客来到出发景点的时刻,出发的景点编号和到达的景点编号。
输出格式
一个整数,表示最小的总旅行时间。
输入输出样例
输入#1
3 3 2
1 4
0 1 3
1 1 2
5 2 3
输出#1
10
说明/提示
【输入输出样例说明】
对D2使用2个加速器,从2号景点到3号景点时间变为2分钟。
公交车在第1分钟从1号景点出发,第2分钟到达2号景点,第5分钟从2号景点出发,第7分钟到达3号景点。
第1个旅客旅行时间 7−0=7 分钟。
第2个旅客旅行时间 2−1=1 分钟。
第3个旅客旅行时间 7−5=2分钟。
总时间7+1+2=10分钟。
【数据范围】
对于10%的数据,k=0;
对于20%的数据,k=1;
对于40%的数据,2≤n≤50,1≤m≤1,000,0≤k≤20,0≤Di≤10,0≤Ti≤500;
对于60%的数据,1≤n≤100,1≤m≤1,000,0≤k≤100,0≤Di≤100,0≤Ti≤10,000;
对于100%的数据,1≤n≤1,000,1≤m≤10,000,0≤k≤100,000,0≤Di≤1000≤Ti≤100,000;
分析
贪心.
使用加速器,肯定是要让其最值得.
求的是所有乘客最少旅行时间,其由到达初始时间和到达目的地时间组成.
就还包含了等待时间.
这就是贪心的缘由,选取一个能够使最多的人的等待时间减少的位置使用加速器.
所以就预处理出不用加速器到达每个地方时间,在依次跑k遍,每一遍选取一个影响人数最多的站台使用加速器.
如果有一条路径,我们使用了加速器后,需要的时间比人最后到的时间早,就是如果要车等人的话,就不必要在把这个往后面减1了,因为无论如何都是之前预处理的最大值了。
注意
有一点值得注意的是,贪心复杂度O(k*n^2),看数据范围感觉会爆掉.但实际跑出来却没有爆,是因为每次因为车等人break就可以去除很多情况.
但是去除车等人这里有个需要注意的,判断当前时间使用加速器是否会等人时,有两个地方,一个在寻找影响的人最多那里,那里判断是当前时间<=人最晚到达时间就break,因为那时还没用加速器,如果相等的话,用加速器就会亏,人都是那个点到,那个点上,不会少等.
还有一个地方,就是使用减速器后的时间,那时判断就是<人最晚的时间才break,这是就不用写=,因为=是从比人最晚+1转移来的,就会使人少等1s,是赚的。
具体还是看代码吧!
参考代码
#include <bits/stdc++.h>
using namespace std;
/*
贪心.
使用加速器,肯定是要让其最值得.
求的是所有乘客最少旅行时间,其由到达初始时间和到达目的地时间组成.
就还包含了等待时间.
这就是贪心的缘由,选取一个能够使最多的人的等待时间减少的位置使用加速器.
所以就预处理出不用加速器到达每个地方时间,在依次跑k遍,每一遍选取一个
影响人数最多的站台使用加速器.
*/
const int N=1e3+50;
const int M=1e4+50;
int n,m,k,dis[N];
struct Kano{
int arr,spos,epos;//人到达时间,到达位置,终点.
}kano[M];//man.
struct Dogmum{
int arr,rarr,rs;//车到达时间,人最晚到达时间,人数.
}dogm[N];//Platform.
int main(){
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<n;i++) scanf("%d",&dis[i]);
for (int i=1;i<=m;i++){
scanf("%d%d%d",&kano[i].arr,&kano[i].spos,&kano[i].epos);
++dogm[kano[i].epos].rs;
dogm[kano[i].spos].rarr=max(dogm[kano[i].spos].rarr,kano[i].arr);
}
int tim=0;
for (int i=1; i<=n; i++){
dogm[i].arr=tim;
tim=max(tim,dogm[i].rarr)+dis[i];
}
while (k--){
int maxxper=0,maxxpos=0;
for (int i=2;i<=n;i++){
if (!dis[i-1]) continue;
int nowper=0;
for (int j=i;j<=n;j++){
nowper+=dogm[j].rs;
if (dogm[j].arr<=dogm[j].rarr) break;
}
if (nowper>maxxper){
maxxper=nowper;
maxxpos=i;
}
}
--dis[maxxpos-1];
for (int i=maxxpos;i<=n;i++){
--dogm[i].arr;
if(dogm[i].arr<dogm[i].rarr)
break;
/*
这里看着和上面的break很像.但这里意义完全不一样.
这里是对使用加速器而被影响的时间-1,如果减了之后等于了人到达的最晚是可以的,会节省1s.
但是上面的那个是不行的,必须写<=.因为那是没用减速器之前.就不能等于,如果在等于的时候减速,就会多消耗1s.
*/
}
}
int res=0;
for (int i=1;i<=m;i++){
res+=dogm[kano[i].epos].arr-kano[i].arr;
}
printf("%d\n",res);
return 0;
}