洛谷P1315 [NOIP2011提高组Day2T3] 观光公交
P1315 观光公交
题目描述
风景迷人的小城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。共一行,包含一个整数,表示最小的总旅行时间。
输入输出样例
3 3 2 1 4 0 1 3 1 1 2 5 2 3
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 ≤ 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题
【题解】
不难发现每辆车到达i的时间reach[i]受到两个限制,一是reach[i - 1] + d[i - 1],二是max(t[i] | a[i] = i),
每使用一次加速器,将其作用于i,能够影响所有b[j] = i + 1的点,以及所有a[j] = i + 1 且 reach(i - 1) + d[i - 1] > max(t[i] | a[i] = i) 的点
递推即可
神奇的1e8过
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #define max(a, b) ((a) > (b) ? (a) : (b)) 6 #define min(a, b) ((a) < (b) ? (a) : (b)) 7 8 inline void read(int &x) 9 { 10 x = 0;char ch = getchar(), c = ch; 11 while(ch < '0' || ch > '9')c = ch, ch = getchar(); 12 while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar(); 13 if(c == '-')x = -x; 14 } 15 16 const int MAXN = 50000 + 10; 17 18 int n,m,k,d[MAXN],t[MAXN],a[MAXN],b[MAXN],ans; 19 20 int mat[MAXN],num[MAXN],reach[MAXN],far[MAXN],sum[MAXN]; 21 22 int main() 23 { 24 read(n), read(m), read(k); 25 for(register int i = 1;i < n;++ i) read(d[i]); 26 for(register int i = 1;i <= m;++ i) read(t[i]), read(a[i]), read(b[i]), ++ num[b[i]], mat[a[i]] = max(mat[a[i]], t[i]), ++sum[b[i]]; 27 for(register int i = 1;i <= n;++ i) reach[i] = max(reach[i - 1], mat[i - 1]) + d[i - 1]; 28 for(register int i = 1;i <= m;++ i) sum[i] += sum[i - 1], ans += reach[b[i]] - t[i]; 29 far[n] = n; 30 for(register int i = n - 1;i >= 1;-- i) 31 { 32 if(mat[i + 1] < reach[i + 1]) 33 far[i] = far[i + 1]; 34 else 35 far[i] = i + 1; 36 } 37 for(;k;--k) 38 { 39 register int ma = 0; 40 for(register int i = 1;i <= n;++ i) 41 { 42 if(d[i] && sum[far[i]] - sum[i] > sum[far[ma]] - sum[ma]) ma = i; 43 } 44 -- d[ma]; 45 if(!ans)break; 46 ans -= sum[far[ma]] - sum[ma]; 47 for(register int i = 1;i <= n;++ i) reach[i] = max(reach[i - 1], mat[i - 1]) + d[i - 1]; 48 for(register int i = n - 1;i >= 1;-- i) 49 { 50 if(mat[i + 1] < reach[i + 1]) 51 far[i] = far[i + 1]; 52 else 53 far[i] = i + 1; 54 } 55 } 56 printf("%d", ans); 57 return 0; 58 }