zoukankan      html  css  js  c++  java
  • 【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
  • 相关阅读:
    并发队列 – 无界阻塞队列 LinkedBlockingQueue 原理探究
    并发队列 – 有界阻塞队列 ArrayBlockingQueue 原理探究
    Java回调机制解读
    一张图看懂encodeURI、encodeURIComponent、decodeURI、decodeURIComponent的区别
    uva 111 History Grading
    hdu 2546 饭卡
    hdu 2602 Bone Collector
    uva 10720 Graph Construction
    uva 10716 Evil Straw Warts Live
    uva 10070 Camel trading
  • 原文地址:https://www.cnblogs.com/g-word/p/3383406.html
Copyright © 2011-2022 走看看