题目描述
风景迷人的小城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该如何安排使用加速器,才能使所有乘客的旅行时间总和最小?
输入输出格式
输入格式:输入文件名为bus.in。
第1 行是3 个整数n, m, k ,每两个整数之间用一个空格隔开。分别表示景点数、乘客数和氮气加速器个数。
第2 行是n-1 个整数,每两个整数之间用一个空格隔开,第i 个数表示从第i 个景点开往第i+1 个景点所需要的时间,即 Di 。
第3 行至m+2 行每行3 个整数 Ti, Ai, Bi,每两个整数之间用一个空格隔开。第 i+2 行表示第i 位乘客来到出发景点的时刻,出发的景点编号和到达的景点编号。
输出格式:输出文件名为bus.out。共一行,包含一个整数,表示最小的总旅行时间。
输入输出样例
说明
【输入输出样例说明】
对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 ≤ T i ≤ 500;
对于60% 的数据,1 ≤ n ≤ 100,1 ≤ m ≤ 1,000,0 ≤ k ≤ 100 ,0 ≤ Di ≤ 100,0 ≤ T i ≤ 10,000 ;
对于100%的数据,1 ≤ n ≤ 1,000,1 ≤ m ≤ 10,000 ,0 ≤ k ≤ 100,000,0 ≤ Di ≤ 100 ,0 ≤ T i ≤ 100,000。
noip2011提高组day2第3题
贪心
参考题解:https://www.luogu.org/blog/bestFy0731/solution-p1315
选择人数最多的两站之间用加速器
#include<iostream>
#include<algorithm>
#include<string.h>
#define Maxn 100009
using namespace std;
struct node
{
int t, s,e;
}a[Maxn];
int d[Maxn]; //i - i + 1这条边的长
int latest[Maxn];//最晚到达i点的人的到达时间
int getto[Maxn];//公交车到达i点的时间
int getoff[Maxn];//在i点下车的人数
int f[Maxn];//i - i+1这条边最多能减少多少时间
int n, m, k;
int main()
{
//freopen("1.txt", "r", stdin);
cin >> n >> m >> k;
for (int i = 1; i <= n - 1; i++)
cin >> d[i];
for (int i = 1; i <= m; i++)
{
cin >> a[i].t >> a[i].s >> a[i].e;
latest[a[i].s] = max(latest[a[i].s], a[i].t);
getoff[a[i].e]++;
}
//没用加速器的公交车到站时间
getto[1] = 0;
for (int i = 2; i <= n; i++)
{
getto[i] = max(getto[i-1],latest[i-1]) + d[i - 1];
}
//开始用加速器
while (k--)
{
/*
每次求的是f[i-1],而求f[i-1]的时候需要用到f[i],也就是先要求出下标较大的f[]值,所以要倒着循环
*/
for (int i = n; i >=2; i--)
{
if (!d[i - 1]) f[i - 1] = 0;
else
{
f[i - 1]=getoff[i];
if (getto[i] > latest[i])f[i - 1] = f[i - 1] + f[i];
/*
也就是公交车到达i这个点的时间是大于最晚的乘客到达i这个点的时间。
那么此时如果(i-1,i)这条边距离减一,相当于能使公交车经过(i,i+1)这条边的时刻变早1个单位,
那么这样其实(i-1,i)距离减一影响到了公交车经过(i,i+1)的时刻,
也就可以当做是需要加上(i,i+1)这条边的距离也减去了1的贡献。
*/
}
}
//选出一个最大的可减去的两站间的时间
int min = 0; int pos=0;
for (int i = 1; i <= n - 1; i++)
{
if (f[i] > min) min=f[i],pos = i;
}
if (!pos)break;//没有就退出
d[pos]--;
//更新pos站后的车到站的时间
for (int i = pos + 1; i <= n ; i++)
{
getto[i] = max(getto[i - 1], latest[i - 1]) + d[i - 1];
}
}
int ans = 0;
for (int i = 1; i <= m; i++)
ans += (getto[a[i].e] - a[i].t);
cout << ans;
return 0;
}