• UVALive-4850 Installations


    题目大意:

    有若干任务, 每个任务有完成消耗的时间和截止的时间.

    如果完成某个任务的时刻是t, 截止时间是d, 那么罚时就是max( 0 , t-d ), 现在求罚时最大的任务和次大的任务的罚时和最少是多少.

    首先很快就可以想到一个贪心的方法: 按照时间限制d排序, 相同就按照安装时间s排序, 都从小到大, 扫一遍就可以了.

    然后就会发现过不了样例.

    那么我们来研究一下这个样例:

    6
    1 7
    4 7
    2 4
    2 15
    3 5
    3 8

    6个任务, 每一行前一个数是s, 表示完成消耗时间, 后一个数是d, 表示时间限制, 每个任务用Ji表示, 这个样例还有下面这个图来辅助解释:

    它按照贪心的方法放的话最大和次大应该是J6和J2, 结果是8, 但是正确答案是J2和J6, 答案是7.

    我们发现其实就是把J6和J2换了位置, 或者说, 是把J2放到了J6的后面.

    但是只交换最大和次大明显是错的, 而把后面的放到前面来只会让大的更大, 那么我们唯一可能的方法就是把前面的放到后面来.

    记一下罚时最大和次大的是哪两个任务, 然后去这两个靠后的一个的位置记为cd, 然后我们枚举cd前面的某一个移动到cd的后面, O( n )扫一遍计算答案, 更新答案, 不断移动. 再和完全不移动直接贪心的答案取min, 这样就可以得到答案了.

    为什么是对的? 首先cd之后的部分是不受移动的影响的, 我们从前面取出来一个放到了cd的后面, 而在cd前面的要么截止时间靠前, 要么处理时间短, 放到cd后面只会成为新的最大值, 而旧的最大和次大其中一个会变成次大值, 就有可能会使答案变小( 答案是最大和次大的和 ).

    为什么只移动一个? 因为把前面的放到cd后面, 结果变成最大, 如果再选一个绝对比原来的次大或者最大要大, 我们新增了两个更大的, 答案明显会更大, 所以只要选择一个交换.

    这样复杂度就是O( n )枚举移动, O( n )计算每一种答案, 总复杂度O( n^2 ).

    移动用链表实现.

    代码如下:

    //made by Crazy01
    #include<bits/stdc++.h>
    #define inf 1<<30
    #define ll long long
    #define db double
    #define c233 cout<<"233"<<endl
    #define mem(s) memset(s,0,sizeof(s))
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    const int N=550;
    using namespace std;
    
    struct lll{
      int tim,lim;
      bool operator <(const lll &a)const{
        return lim==a.lim?tim<a.tim:lim<a.lim;
      }
    }job[N];
    int n,T,ans,cd,r[N];
    
    inline int gi(){
      int x=0,res=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
      while(ch<='9'&&ch>='0')x=(x<<1)+(x<<3)+ch-48,ch=getchar();
      return x*res;
    }
    
    void init(){
      n=gi(); r[0]=1;
      for(int i=1;i<=n;i++)
        job[i].tim=gi(),job[i].lim=gi(),r[i]=i+1;
      sort(job+1,job+1+n);
    }
    
    int calc(){
      int t=0,max1=0,max2=0;
      cd=0;
      for(int i=r[0];i<=n;i=r[i]){
        t+=job[i].tim;
        int tle=max(0,t-job[i].lim);
        if(tle>max1)max2=max1,max1=tle,cd=i;
        else if(tle>max2)max2=tle,cd=i;
      }
      return max1+max2;
    }
    
    void work(){
      if(!ans){printf("%d
    ",ans); return;}  
      for(int i=r[0],end=cd;i<end;i=r[i]){
        r[i-1]=r[i]; r[i]=r[end]; r[end]=i;
        ans=min(ans,calc());
        r[end]=r[i]; r[i]=r[i-1]; r[i-1]=i; 
      }
      printf("%d
    ",ans);
    }
    
    int main(){
      T=gi();
      while(T--){
        mem(job);
        init();
        ans=calc();
        work();
      }
      return 0;
    }
  • 相关阅读:
    Java内存模型
    Redis的复制特性
    Redis数据持久化
    Java的三种代理模式
    设计模式—模板方法模式
    设计模式—观察者模式
    web性能优化之:no-cache与must-revalidate深入探究
    JWT
    数值每三位加逗号
    Webpack 打包优化之速度篇
  • 原文地址:https://www.cnblogs.com/Crazy01/p/7683751.html
Copyright © 2020-2023  润新知