二分答案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; }