「NOIp-2011」D2-T3 观光公交

解题思路


一开始自己想了一个贪心,虽然贪心的主要思路是对的,但并不会统计游客用的旅行时间。所以就去题解里面看看,第一篇是最小费用最大流,会比较麻烦,所以就去看了看底下的贪心,第一篇贪心被卡掉了,看第二篇,嗯,好像还行。再看看第三篇,写的好简略。不过看懂了。

贪心的主要思路就是在经过游客最多的路上使用加速器,但是还要注意,如果在一条路径的终点,有的游客到达的时间比现在公交车到达的时间还要晚的话就没必要用加速器了,因为再早到达你也必须等着游客上车吧。

考虑用优先队列保证得到最大的价值(经过的游客的数量),如果有一个点满足下面的条件:

最晚到达的乘客的到达时间比公交车的到达时间还要晚。

那就将整段路程从这里分开,分别去考虑劈开后的路程。

昨晚上面这些再来考虑如何处理每段路程。找一下这段路程中,每两个点之间的路途上,最短的等待时间,这就是要使用(用作用)的加速器数量的最大值。(因为超过了这个值就不会再有影响了)

代码


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
inline int read() {
int x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while (c <= '9' && c >= '0') {x = x*10 + c-'0'; c = getchar();}
return x * f;
}
const int maxn = 1003;
struct node {
int l, r, tim, val;
}tmp;
int n, m, k, v[maxn], a[maxn], b[maxn], d[maxn], ans;
bool operator < (const node &a, const node &b) {
return a.val > b.val;
}
priority_queue<node> Q;
inline void sol(int l, int r) {
if(l >= r) return ;
if(d[l] == 0) {sol(l+1, r); return ;}
for(int i=l+1; i<r; i++)
if(a[i] >= b[i]) {
sol(l, i), sol(i, r);
return ;
}
int mn = d[l], val = v[r];
for(int i=l+1; i<r; i++) {
mn = min(mn, b[i]-a[i]);
val += v[i];
}
d[l] -= mn;
for(int i=l+1; i<r; i++) b[i] -= mn;
Q.push((node){l, r, mn, val});
}
int main() {
n = read(), m = read(), k = read();
for(int i=1; i<n; i++) d[i] = read();
int x, y, z;
for(int i=1; i<=m; i++) {
z = read(), x = read(), y = read();
a[x] = max(a[x], z);
ans -= z;
v[y] ++;
}
for(int i=2; i<=n; i++) b[i] = max(b[i-1], a[i-1]) + d[i-1];
for(int i=2; i<=n; i++) ans += b[i] * v[i];
for(sol(1, n); !Q.empty()&&k!=0; ) {
tmp = Q.top(), Q.pop();
ans -= min(tmp.tim, k) * tmp.val;
k -= min(tmp.tim, k);
if(k != 0) sol(tmp.l, tmp.r);
}
printf("%d", ans);
}