vijos1741 观光公交 (贪心)

https://www.vijos.org/p/1741

P1741观光公交
请登录后递交
 

描述

风景迷人的小城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该如何安排使用加速器,才能使所有乘客的旅行时间总和最小?

格式

输入格式

第1行是3个整数n, m, k,每两个整数之间用一个空格隔开。分别表示景点数、乘客数和氮气加速器个数。

第2行是n-1个整数,每两个整数之间用一个空格隔开,第i个数表示从第i个景点开往第i+1个景点所需要的时间,即Di。

第3行至m+2行每行3个整数Ti, Ai, Bi,每两个整数之间用一个空格隔开。第i+2行表示第i位乘客来到出发景点的时刻,出发的景点编号和到达的景点编号。

输出格式

共一行,包含一个整数,表示最小的总旅行时间。

样例1

样例输入1[复制]

3 3 2
1 4
0 1 3
1 1 2
5 2 3

样例输出1[复制]

10

限制

1s

提示

样例说明:

对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第三题

大意:题目说得很清楚,我都怕。

题解:贪心,一个个选择氮气加速的位置。

首先我们看乘客所花时间和怎么计算,容易得到一个乘客所花的时间等于

ar[b[i]] - T[i]

其中b[i]为该乘客的终点,ar[x]为到达x站的时间,T[i]为该乘客出发的时间。

我们把到达x的乘客统计,cntto[x]为到达x的乘客的数量,然后所有乘客所花的时间和,就是sum(cntto[i]*ar[i])-sumT,cntto和sum都是已知的,关键在于ar。

设st[i]为从i出发的最晚一名游客的出现时间,这样我们可以用st[i]和d[i]来从头到尾得到各个点的ar[i]。

for(i=1; i<n; i++) artime[i]=max(artime[i-1],st[i-1])+d[i-1];

 

然后我们一个个氮气加速分别考虑,每次贪心放在能减少时间总和最多的位置。对每个位置计算,向后推若干个ar[i]>st[i],即有发展潜力的位置,(若ar[i]<=st[i],则减少ar[i]也无法减少之后游客的时间)。

 1             for(i=0; i<n-1; i++) {
 2                 if(d[i]>0) {
 3                     canup=cntto[i+1];
 4                     j=i+1;
 5                     while(j+1<n && artime[j]>st[j])canup+=cntto[j+1],j++;
 6                     //cout<<i<<','<<j<<endl;
 7                     if(canup>maxup) {
 8                         maxup=canup;
 9                         maxi=i;
10                     }
11                 }
12             }

这样我们就在maxi处氮气加速,效果最碉。

重复多次,用完所有氮气加速,完成。

 1 //#pragma comment(linker, "/STACK:102400000,102400000")
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<iostream>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<cmath>
 8 #include<map>
 9 #include<set>
10 #include<stack>
11 #include<queue>
12 using namespace std;
13 #define ll long long
14 #define usint unsigned int
15 #define mz(array) memset(array, 0, sizeof(array))
16 #define minf(array) memset(array, 0x3f, sizeof(array))
17 #define REP(i,n) for(i=0;i<(n);i++)
18 #define FOR(i,x,n) for(i=(x);i<=(n);i++)
19 #define RD(x) scanf("%d",&x)
20 #define RD2(x,y) scanf("%d%d",&x,&y)
21 #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
22 #define WN(x) printf("%d\n",x);
23 #define RE  freopen("D.in","r",stdin)
24 #define WE  freopen("1biao.out","w",stdout)
25 
26 const int maxn=1111;
27 const int maxm=11111;
28 int d[maxn],T[maxm],a[maxm],b[maxm];
29 int st[maxn],artime[maxn];
30 int cntto[maxn];
31 int canup[maxn];
32 int n,m,k;
33 ll Tsum;
34 
35 int main() {
36     int i,j;
37     int maxi,maxup,canup;
38     ll ans;
39     while(scanf("%d%d%d",&n,&m,&k)!=EOF) {
40         REP(i,n-1) scanf("%d",&d[i]);
41         mz(st);
42         mz(cntto);
43         Tsum=0;
44         REP(i,m) {
45             scanf("%d%d%d",&T[i],&a[i],&b[i]);
46             a[i]--;b[i]--;
47             if(st[a[i]]<T[i])st[a[i]]=T[i];
48             cntto[b[i]]++;
49             Tsum+=T[i];
50         }
51         artime[0]=0;
52         for(i=1; i<n; i++) artime[i]=max(artime[i-1],st[i-1])+d[i-1];
53         while(k>0) {
54             maxi=-1;
55             maxup=-1;
56             for(i=0; i<n-1; i++) {
57                 if(d[i]>0) {
58                     canup=cntto[i+1];
59                     j=i+1;
60                     while(j+1<n && artime[j]>st[j])canup+=cntto[j+1],j++;
61                     //cout<<i<<','<<j<<endl;
62                     if(canup>maxup) {
63                         maxup=canup;
64                         maxi=i;
65                     }
66                 }
67             }
68             d[maxi]--;
69             //printf("WOW,%d!",maxi);
70             artime[0]=0;
71             k--;
72             for(i=1; i<n; i++) artime[i]=max(artime[i-1],st[i-1])+d[i-1];
73         }
74         ans=-Tsum;
75         for(i=1; i<n; i++)
76             ans+=artime[i]*cntto[i];
77         printf("%lld\n",ans);
78     }
79     return 0;
80 }
View Code

 

转载于:https://www.cnblogs.com/yuiffy/p/3900171.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值