【noip2011】观光公交

题解:

做这题的时候为了敢速度- - 直接orz了神小黑的题解

 

其实我还是有想一个拙计的方法的- -

dp:f[i][j] 表示到i点使用j个加速器 在i前上车的人的时间和

轻松愉悦转移之 - - 但是有很严重的两个问题

1.空间复杂度O(nk)爆掉

2.时间复杂度O(nk^2)更呵呵- -

于是弃疗

 

正解:

贪心!

time[i]表示到i点的时间

last[i]表示从i出发的人的最晚到达的时间

sum[i]表示在i或i前下车的人数

f[i]表示在i后time[j]<=last[j]的最小j

贪心每个加速器在哪使用

选出使sum[f[i]]-sum[i]最大的i

 

证明:

显然每次使用加速器都要在能让最多人加速的地方使用

而如果在i点使用加速器 我能使在i+1到f[i]下车的人都加速

超过f[i]下车的由于要在f[i]车站等人 所以相当于没加速

sum[f[i]]-sum[i] 即为在i+1到f[i]下车的人

 

优化:

orz神ak想出的优化

我们在选出i的同时 显然可以同时使用好几个加速器 只要使用后i+1到f[i]-1没有 time[j]<last[j]

于是我们可以统计i+1到f[i]-1中last[j]-time[j]的最小值 直接使用这么多

注意 如果这个最小值大于剩余的加速器 或大于i到i+1所需的时间 那么取他们的最小值

原来的时间复杂度为O(nk) 而这样做复杂度为O(n^2)

因为对于任意一对(i,f[i])如果他们被加速过 那么之后就不可能再加速了

 

代码:

 1 #include <cstdio>
 2 const int N=1002;
 3 struct info{
 4     int x,y,t;
 5     info(const int a=0,const int b=0,const int c=0):
 6         x(a),y(b),t(c){}
 7 }im[100001];
 8 int n,m,k,out[N],ti[N],last[N],sum[N],lon[N],ans;
 9 int max(int x,int y){ return x>y ? x : y; }
10 void work(){
11     while (k){
12         int x=0,y,z;
13         for (int i=n,la=n,min=100000;i>=1;i--){
14             if (sum[la]-sum[i]>x && lon[i+1]){
15                 x=sum[la]-sum[i];
16                 y=i;
17                 z=min;
18                 if (lon[i+1]<z) z=lon[i+1];
19             }
20             if (i<n)
21             if (min>ti[i]-last[i]) min=ti[i]-last[i];
22             if (ti[i]<=last[i]){
23                 la=i;
24                 min=100000;
25             }
26         }
27         if (z>k) z=k;
28         k-=z;
29         ans-=x*z;
30         lon[y+1]-=z;
31         for (int i=y+1;i<=n && ti[i]>last[i];i++) ti[i]-=z;
32     }
33 }
34 void maketi(){
35     for (int i=1;i<=n;i++){
36         sum[i]=sum[i-1]+out[i];
37         ti[i]=max(ti[i-1],last[i-1])+lon[i];
38     }
39 }
40 int main(){
41     scanf("%d%d%d",&n,&m,&k);
42     int x,y,z;
43     for (int i=2;i<=n;i++) scanf("%d",&lon[i]);
44     for (int i=1;i<=m;i++){
45         scanf("%d%d%d",&x,&y,&z);
46         im[i]=info(y,z,x);
47         last[y]=max(last[y],x);
48         ++out[z];
49     }
50     maketi();
51     for (int i=1;i<=m;i++) ans+=ti[im[i].y]-im[i].t;
52     work();
53     printf("%d",ans);
54 }
View Code

 

转载于:https://www.cnblogs.com/g-word/p/3383406.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值