题目描述
P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为1…N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<=K<=j 制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为x,其制作费用为(X-L)^2.其中L是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过L。但他希望费用最小.
输入输出格式
输入格式:
第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7
输出格式:
输出最小费用
输入输出样例
输入样例#1:
5 4
3
4
2
1
4
输出样例#1:
1
分析:
动态规划:f[i]表示前i个玩具装起来的最小费用
s[i]表示前i个玩具的长度和
假设是j到i这段玩具,则状态转移方程:f[i]:=min{f[i],f[j-1]+sqr(i-j+s[i]-s[j-1]-l)},其中1<=j小于i
计算f[i]时,i,s[i],l这些量都是已知,而含有j的f[j-1],j,s[j-1]是未知的,展开平方式
注意参数分离,定义d[i]=i+s[i]-l,c[j]=j+s[j-1];
则有f[i]:=f[j-1]+sqr(d[i]-c[i])=f[j-1]+sqr(d[i])+sqr(c[i])-2*d[i]*c[i];
————-讨论单调性
最基本:j2>j1,f[i]j1>f[i]j2则可以删除j1(表示的是i能从j1,和j2两个决策过来)
深入:
f[i]j1小于f[i]j2
f[j1-1]+sqr(d[i])+sqr(c[j1])-2*d[i]*c[j1]>f[j2-1]+sqr(d[i])+sqr(c[j2])-2*d[i]*c[j2]
(f[j1-1]+sqr(c[j1]))-(f[j2-1]+sqr(c[j2]))>2*d[i]*(c[j2]-c[j1]);
令y[i]:=f[i-1]+sqr(c[i])
即y[j1]-y[j2]>2*d[i]*(c[j2]-c[j1])
(y[j2]-y[j1])/(c[j2]-c[j1])<2*d[i]
像这样两点形成的斜率,即为斜率优化
令T(J1,J2):=(y[j2]-y[j1])/(c[j2]-c[j1]);
斜率优化:
计算f[i]时,决策j2>j1,如果决策j2优于j1,则满足T(j1,j2)<2*d[i];
c[i]和d[i]都是递增的
程序实现
为了始终维护2*d[i]小于T(j1,j2)小于………小于T(jn-1,jn)
删尾:如果T(jr-1,jr)>T(jr,i) 则删掉r
插入
删头:如果T(j1,j2)<2*d[i],则删掉j1
取头
program df;
var i,j,n,m:longint;
k,t,l,r:int64;
a,f,c,d,q,s:array[0..100000] of int64;
function deal(x:int64):int64;
begin
exit(f[x-1]+sqr(c[x]));
end;
function check(x,y:int64):real; //求取T(x,y)的值
var i,j:int64;
begin
j:=deal(y)-deal(x);
i:=c[y]-c[x];
exit(j/i);
end;
begin
readln(n,m);
for i:=1 to n do
begin
readln(a[i]);
s[i]:=s[i-1]+a[i];
end;
for i:=1 to n do
begin
d[i]:=i+s[i]-m;
c[i]:=i+s[i-1];
end;
l:=1; r:=0;
for i:=1 to n do
begin
while (r>l) and (check(q[r-1],q[r])>check(q[r],i)) do dec(r); //保证T(r-1,r)小于T(r,i)
inc(r);
q[r]:=i;
while (r>l) and (check(q[l],q[l+1])<2*d[i]) do inc(l); //保证T(1,2)>2*d[I],即确保递增
f[i]:=f[q[l]-1]+sqr(d[i]-c[q[l]]);
end;
writeln(f[n]);
end.