1139 观光公交
2011年NOIP全国联赛提高组
题目描述 Description
风景迷人的小城 Y 市,拥有n 个美丽的景点。由于慕名而来的游客越来越多,Y 市特意安排了一辆观光公交车,为游客提供更便捷的交通服务。观光公交车在第0 分钟出现在1号景点,随后依次前往2、3、4……n 号景点。从第i 号景点开到第i+1 号景点需要Di 分钟。任意时刻,公交车只能往前开,或在景点处等待。
设共有 m 个游客,每位游客需要乘车1 次从一个景点到达另一个景点,第i 位游客在Ti 分钟来到景点Ai,希望乘车前往景点Bi(Ai<Bi)。为了使所有乘客都能顺利到达目的地,公交车在每站都必须等待需要从该景点出发的所有乘客都上车后才能出发开往下一景点。
假设乘客上下车不需要时间。
一个乘客的旅行时间,等于他到达目的地的时刻减去他来到出发地的时刻。因为只有一辆观光车,有时候还要停下来等其他乘客,乘客们纷纷抱怨旅行时间太长了。于是聪明的司机ZZ 给公交车安装了k 个氮气加速器,每使用一个加速器,可以使其中一个Di 减1。对于同一个Di 可以重复使用加速器,但是必须保证使用后Di 大于等于0。
那么 ZZ 该如何安排使用加速器,才能使所有乘客的旅行时间总和最小?
输入描述 Input Description
第 1 行是3 个整数n, m, k,每两个整数之间用一个空格隔开。分别表示景点数、乘客数和氮气加速器个数。
第 2 行是n-1 个整数,每两个整数之间用一个空格隔开,第i 个数表示从第i 个景点开往第i+1 个景点所需要的时间,即Di。
第 3 行至m+2 行每行3 个整数Ti, Ai, Bi,每两个整数之间用一个空格隔开。第i+2 行表示第i 位乘客来到出发景点的时刻,出发的景点编号和到达的景点编号。
数据范围及提示 Data Size & Hint
对 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 ≤ 100,0 ≤ Ti ≤ 100,000。
题解:
本题为NOIP2011提高组day2第三题,其实这道题虽然被放在第三题但它仅仅只需要一个贪心就好,我们首先记录下来到每一站下车的人数,然后枚举每一个加速器,由于每个乘客的旅行时间只与他到达的时间与下车的时间有关,因此,我们在枚举每一个加速器的时候,只需要把能够造福最多人的那一段路加速即可,于是我们可以记录每一段路所造福的人数,我们暂定每个景点的出发时间为需要从该景点上车的最晚到达的乘客,那么到达时间即为上一个景点的出发时间或到达时间更大的一个值加上从上一个景点到该景点所需要的时间。如果某个景点的出发时间小于到达时间,那么说明若在这段旅程中使用加速器,能够造福到下一个景点下车的人。通过这个,我们就可以贪心了,然后每次贪心完之后都更新到达景点的时间即可。为了方便计算,我在初始化的时候把所有人的到达景点的时间都减去,这样就不用最后再减了,就可以直接求需要在每个景点下车的人数*到达该景点的时间的和就行了。
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define N 11000
int d[N],num[N],data[N],tim[N],last[N];
int n,m,k,ans,max1,cct;
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=2;i<=n;i++) scanf("%d",&d[i]);
for(int i=1,a,b,c;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
ans-=a;
num[c]++;
last[b]=max(last[b],a);
}
for(int i=2;i<=n;i++){
tim[i]=max(tim[i-1],last[i-1])+d[i];
}
for(int i=1;i<=k;i++){
for(int j=n;j>=2;j--){
data[j]=num[j];
if(last[j]<tim[j]){
data[j]+=data[j+1];
}
}
max1=0;
for(int j=2;j<=n;j++){
if(data[j]>max1&&d[j]>0){
max1=data[j];
cct=j;
}
}
d[cct]--;
for(int j=cct;j<=n;j++){
tim[j]=max(tim[j-1],last[j-1])+d[j];
}
}
for(int i=2;i<=n;i++){
ans+=num[i]*tim[i];
}
printf("%d\n",ans);
return 0;
}