P3195 [HNOI2008]玩具装箱TOY

题目描述

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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值