zoukankan      html  css  js  c++  java
  • BZOJ2587 : [Ceoi2011]Team

    将球员按限制从大到小排序,那么最优解中每支球队都是一个连续的区间。

    设$f[i]$表示前$i$大的球员成功组队时,最多能组的队伍数,$g[i]$表示此时最大人数的最小值。

    那么$f[i]=max(f[j]+1),a[j]geq i-j$,即$a[j]+jgeq i$。

    注意到$a[j]+j>j$恒成立,所以可以使用链表来维护,当计算$f[a[j]+j]$时,才将$j$加入决策范围中。

    此时需要维护决策中$f$的最大值,对于多个最大值,则要让$max(g[j],i-j)$最小。

    $1.$若$g[j]leq i-j$,即$g[j]+jleq i$,那么同样可以使用链表来维护,$j$最大的是最优决策。

    $2.$若$g[j]>i-j$,那么这些$j$还在后面的链表里,使用堆来维护$g[j]$最小的$j$即可。

    时间复杂度$O(nlog n)$。

    #include<cstdio>
    const int N=1000010,BUF=10000000,OUT=10000000;
    char Buf[BUF],*buf=Buf,Out[OUT],*ou=Out;int Outn[30],Outcnt;
    int n,i,j,x=-1,a[N],b[N],c[N],f[N],g[N],w[N],g0[N],nxt0[N],g1[N],nxt1[N],h[N],l;
    inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;}
    inline void write(int x){
      for(Outcnt=0;x;x/=10)Outn[++Outcnt]=x%10+48;
      while(Outcnt)*ou++=Outn[Outcnt--];
    }
    inline void swap(int&a,int&b){int c=a;a=b;b=c;}
    inline bool cmp(int x,int y){
      if(f[x]!=f[y])return f[x]>f[y];
      return g[x]<g[y];
    }
    inline void pop(){
      h[1]=h[l--];
      for(int i=1;;){
        int t=h[i],j=0;
        if((i<<1)<=l&&cmp(h[i<<1],t))t=h[j=i<<1];
        if((i<<1|1)<=l&&cmp(h[i<<1|1],t))j=i<<1|1;
        if(j)swap(h[i],h[j]),i=j;else return;
      }
    }
    inline void add0(int x){
      int y=x+b[x+1];
      if(y>n)return;
      nxt0[x]=g0[y];g0[y]=x;
    }
    inline void add1(int x){
      h[++l]=x;
      for(int i=l;i>1&&cmp(h[i],h[i>>1]);i>>=1)swap(h[i],h[i>>1]);
      int y=x+g[x];
      if(y>n)return;
      nxt1[x]=g1[y];g1[y]=x;
    }
    inline void up(int y){
      if(x<0){x=y;return;}
      if(f[y]>f[x]||f[y]==f[x]&&y>x)x=y;
    }
    inline void use(int y){
      int z=g[y]>i-y?g[y]:i-y;
      if(f[y]+1>f[i])f[i]=f[y]+1,g[i]=z,w[i]=y;
      else if(f[y]+1==f[i]&&z<g[i])g[i]=z,w[i]=y;
    }
    int main(){
      fread(Buf,1,BUF,stdin);read(n);
      for(i=1;i<=n;i++)read(a[i]),b[a[i]]++;
      for(i=n;i;i--)b[i]+=b[i+1];
      for(i=1;i<=n;i++)c[b[a[i]]--]=i;
      for(i=1;i<=n;i++)b[i]=a[c[i]],f[i]=g0[i]=g1[i]=-1;
      for(add0(f[0]=0),i=1;i<=n;i++){
        for(j=g0[i];~j;j=nxt0[j])if(g[j]+j<=i)up(j);else add1(j);
        for(j=g1[i];~j;j=nxt1[j])up(j);
        if(~x)use(x);
        while(l){
          j=h[1];
          if(g[j]+j>i){use(j);break;}
          pop();
        }
        if(f[i]>0)add0(i);
      }
      write(f[n]);*ou++='
    ';
      while(n){
        j=w[n];
        write(n-j);
        for(i=j+1;i<=n;i++)*ou++=' ',write(c[i]);
        *ou++='
    ';
        n=j;
      }
      fwrite(Out,1,ou-Out,stdout);
      return 0;
    }
  • 相关阅读:
    进程空间与系统空间(一)
    内核之最
    Linux 内核3.10.5 专场
    device_create与device_register
    重写与重载的含义
    抽象类和接口的区别
    Spring知识点
    mybatis学习
    知识点
    Mybatis面试题
  • 原文地址:https://www.cnblogs.com/clrs97/p/6603152.html
Copyright © 2011-2022 走看看