dp+单调性+平衡树
在看某篇论文中看到这道题,但是那篇论文不如这个http://www.cnblogs.com/staginner/archive/2012/04/02/2429850.html 大神的空间写的好(还是说我太弱需要详解……)。
其实要说的在大神的博客里面已经说的很好……
比如f[i],然后j表示满足a[j+1]+a[j+2]+……+a[i]<=m的最小值。然后我们假定a[j]--a[i]中最大数的下标为k,那么就有j+1<=l<=k时,f[j+1]+a[k]<=f[j+2]+a[k]<=f[j+3]+a[k]……<=f[k-1]+a[k],也就是只要在把在k前或者k到i的区间分为一个区间,那么这个区间的最大值就是a[k]。这样f数组就是递增的。
var
left,right,s,q,d:array[..]of longint;
key,a,sum,f:array[..]of int64;
i,j,k,l,n,tot,t,head,tail,deci:longint;
m:int64; procedure rightrotate(var t:longint);
var
k:longint;
begin
k:=left[t];
left[t]:=right[k];
right[k]:=t;
s[k]:=s[t];
s[t]:=s[left[t]]+s[right[t]]+;
t:=k;
end; procedure leftrotate(Var t:longint);
var
k:longint;
begin
k:=right[t];
right[t]:=left[k];
left[k]:=t;
s[k]:=s[t];
s[t]:=s[left[t]]+s[right[t]]+;
t:=k;
end; procedure maintain(var t:longint);
begin
if s[left[left[t]]]>s[right[t]] then begin
rightrotate(t);
maintain(right[t]);
maintain(t);
end;
if s[right[left[t]]]>s[right[t]] then begin
leftrotate(left[t]);
rightrotate(t);
maintain(left[t]);
maintain(right[t]);
maintain(t);
end;
if s[right[right[t]]]>s[left[t]] then begin
leftrotate(t);
maintain(left[t]);
maintain(t);
end;
if s[left[right[t]]]>s[left[t]] then begin
rightrotate(right[t]);
leftrotate(t);
maintain(left[t]);
maintain(right[t]);
maintain(t);
end;
end; procedure insert(var t:longint;v:int64);
begin
if t= then begin
inc(tot);
t:=tot;
key[t]:=v;
s[t]:=;
left[t]:=;
right[t]:=;
end
else begin
inc(s[t]);
if v<key[t] then insert(left[t],v)
else insert(right[t],v);
maintain(t);
end;
end; function delete(var t:longint;v:int64):int64;
begin
dec(s[t]);
if (key[t]=v) or( (v<key[t]) and (left[t]=) )or ((v>=key[t]) and (right[t]=)) then begin
delete:=key[t];
if (left[t]=) or (right[t]=) then
t:=left[t]+right[t]
else key[t]:=delete(left[t],key[t]+);
end
else
if v<key[t] then
delete:=delete(left[t],v)
else delete:=delete(right[t],v);
end; function searchmin(var t:longint):int64;
begin
if left[t]= then exit(key[t]);
exit(searchmin(left[t]));
end; function into:boolean;
begin
readln(n,m);
sum[]:=;
for i:= to n do begin
read(a[i]);
sum[i]:=sum[i-]+a[i];
if a[i]>m then exit(false);
end;
exit(true);
end; begin
if into then begin
t:=;
tot:=;
head:=;
tail:=;
deci:=;
for i:= to n do begin
while sum[i]-sum[deci]>m do inc(deci);
while (head<tail) and (q[head]<=deci) do begin
delete(t,f[d[head]]+a[q[head]]);
inc(head);
end;
while (head<tail) and (a[i]>=a[q[tail-]]) do begin
delete(t,f[d[tail-]]+a[q[tail-]]);
dec(tail);
end;
q[tail]:=i;
if head<tail then
d[tail]:=q[tail-]
else d[tail]:=deci;
insert(t,f[d[tail]]+a[i]);
inc(tail);
if d[head]<deci then begin
delete(t,f[d[head]]+a[q[head]]);
d[head]:=deci;
insert(t,f[deci]+a[q[head]]);
end;
f[i]:=searchmin(t);
end;
writeln(f[n]);
end
else writeln('-1');
readln;
readln;
end.