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