BZOJ2862 : 分糖果

二分答案$x$表示最大的一段的和。

设$f[i]$表示前$i$个最多分几段,满足最大的一段不超过$x$,若$f[n]\geq k$,则可行,

则$f[i]=\max(f[j])+1,sum[i]-sum[j]\leq x$。

用Treap优化DP,$O(n\log^2n)$。

同理再次二分得到最小的$x$,使得该限制下最少的段数$\leq k$。

则$ans=\max(x_0,x_1)$。

 

#include<cstdio>
#include<cstdlib>
const int N=20010,inf=1000000000;
int n,k,i,l,r,mid,ans0,ans1,f,sum[N];
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a<b?a:b;}
struct node{
  int p,val,vmx,vmi,mx,mi;node*l,*r;
  node(){val=p=0,vmx=mx=-inf,vmi=mi=inf;l=r=NULL;}
  inline void up(){
    mx=max(vmx,max(l->mx,r->mx));
    mi=min(vmi,min(l->mi,r->mi));
  }
}*blank=new(node),pool[N],*cur=pool,*T;
inline void Rotatel(node*&x){node*y=x->r;x->r=y->l;x->up();y->l=x;y->up();x=y;}
inline void Rotater(node*&x){node*y=x->l;x->l=y->r;x->up();y->r=x;y->up();x=y;}
void Ins(node*&x,int p,int v){
  if(x==blank){
    x=cur++;x->val=p;x->l=x->r=blank;x->vmx=x->mx=x->vmi=x->mi=v;x->p=std::rand();
    return;
  }
  x->mx=max(x->mx,v);
  x->mi=min(x->mi,v);
  if(p==x->val){
    x->vmx=max(x->vmx,v);
    x->vmi=min(x->vmi,v);
    return;
  }
  if(p<x->val){
    Ins(x->l,p,v);
    if(x->l->p>x->p)Rotater(x);
  }else{
    Ins(x->r,p,v);
    if(x->r->p>x->p)Rotatel(x);
  }
}
int Askmx(node*&x,int p){
  if(x==blank)return -inf;
  if(p==x->val)return max(x->vmx,x->r->mx);
  if(p<x->val)return max(x->vmx,max(x->r->mx,Askmx(x->l,p)));
  return Askmx(x->r,p);
}
int Askmi(node*&x,int p){
  if(x==blank)return inf;
  if(p==x->val)return min(x->vmi,x->r->mi);
  if(p<x->val)return min(x->vmi,min(x->r->mi,Askmi(x->l,p)));
  return Askmi(x->r,p);
}
int main(){
  blank->l=blank->r=blank;
  scanf("%d%d",&n,&k);
  for(i=1;i<=n;i++)scanf("%d",&sum[i]),sum[i]+=sum[i-1];
  l=-inf,r=ans0=ans1=inf;
  while(l<=r){
    mid=(l+r)>>1;
    cur=pool,Ins(T=blank,0,0);
    for(i=1;i<=n;i++)Ins(T,sum[i],f=Askmx(T,sum[i]-mid)+1);
    if(f>=k)r=(ans0=mid)-1;else l=mid+1;
  }
  l=-inf,r=inf;
  while(l<=r){
    mid=(l+r)>>1;
    cur=pool,Ins(T=blank,0,0);
    for(i=1;i<=n;i++)Ins(T,sum[i],f=Askmi(T,sum[i]-mid)+1);
    if(f<=k)r=(ans1=mid)-1;else l=mid+1;
  }
  return printf("%d",max(ans0,ans1)),0;
}

  

posted @ 2015-02-01 20:42  Claris  阅读(720)  评论(0编辑  收藏  举报