BZOJ2862 : 分糖果

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

设f[i]表示前i个最多分几段,满足最大的一段不超过x

则f[i]=max(f[j])+1,sum[i]-sum[j]<=x

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

 

#include<cstdio>

#include<cstdlib>

const int N=20010,inf=1000000000;

int n,k,i,l=-inf,r=inf,mid,ans,f,sum[N];

inline int max(int a,int b){return a>b?a:b;}

struct node{

  int p,val,v,mx;node*l,*r;

  node(){val=p=0,v=mx=-inf;l=r=NULL;}

  inline void up(){mx=max(v,max(l->mx,r->mx));}

}*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->v=x->mx=v;x->p=std::rand();

    return;

  }

  x->mx=max(x->mx,v);

  if(p==x->val){x->v=max(x->v,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 Ask(node*&x,int p){

  if(x==blank)return -inf;

  if(p==x->val)return max(x->v,x->r->mx);

  if(p<x->val)return max(x->v,max(x->r->mx,Ask(x->l,p)));

  return Ask(x->r,p);

}

bool check(int x){

  cur=pool,Ins(T=blank,0,0);

  for(i=1;i<=n;i++)Ins(T,sum[i],f=Ask(T,sum[i]-x)+1);

  return f>=k;

}

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];

  while(l<=r)if(check(mid=(l+r)>>1))r=(ans=mid)-1;else l=mid+1;

  return printf("%d",ans),0;

}

  

 

你可能感兴趣的:(ZOJ)