重點在講斜率優化
description
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。但他希望費用最小.
input
第一行輸入兩個整數n,l.接下來n行輸入ci.1<=n<=50000,1<=l,ci<=10^7
output
輸出最小費用
5 4342
141dp先入腦
有乙個dp[i]:=min(dp[j]+(sum[i]-sum[j]+i-j-1-l)^2)
的基本思路
預處理可以得到
f[i]:=sum[i]+i
;令c=l+1
可以簡化方程:
dp[i]:=min(dp[j]+(f[i]-f[j]-c)^2))
明顯這個為o(n^2)的演算法,,要再簡化;
一維的dp可以想到
斜率優化
所謂斜率優化,個人的感悟就是:
當 i:1-->n j:1-->n的n^2迴圈時 可以簡化j的迴圈 把1~n依次入隊出隊,當i要選擇j時,先根據最優策略縮短佇列,再在選取隊首元素直接作為j,算出dp[i];
這樣做的話每個數進出一次佇列 複雜度就變為o(n);
但是這樣做必須證明單調性,也就是出隊的元素在以後的dp中不會再被利用
下面說說怎麼縮短佇列
dp[i]:=min(dp[j]+(f[i]-f[j]-c)^2))
中j的選擇是決定dp[i]的大小的 而 f[i]、c這樣的常量是不變的(對於同乙個i來說)
所以我們把不含j的變數分離出來,方便運算
dp[i]:=min(dp[j]+f[j]^2-2f[i]f[j]+2f[j]*c)+f[i]^2+c^2-2*f[i]*c;
假設選j好過選k,
本題為
dp[j]+f[j]^2-2f[i]f[j]+2f[j]*c<
dp[k]+f[k]^2-2f[i]f[k]+2f[k]*c
化簡分離i
dp[j]-dp[k]+(f[i]-f[k])*(2c+f[j]+f[k])
-------------------------------------------
2(f[j]-f[k])
簡化其為
com(j,k)
也就是說 『選j好過選k』當且僅當『
com(j,k)成立』
所以如果乙個佇列的頭依次為a,b 如果g(b,a)<
=f[i] 那麼把a刪了吧
q[1]:=0;
head:=1;
tail:=1;
for i:=1 to n do
begin
while (head<=tail-1)and(com(q[head],q[head+1])<=sum[i]) do
inc(head);
dp[i]:=dp[q[head]]+(f[i]-f[q[head]]-l-1)*(f[i]-f[q[head]]-l-1);
while (head<=tail-1)and(com(q[tail-1],q[tail])>=com(q[tail],i)) do
dec(tail);
inc(tail);
q[tail]:=i;
end;
end;
這就是所謂的斜率優化
HNOI2008 玩具裝箱toy
dp i min dp j sum i sum j c 2 dp k sum i sum k c 2 dp k si sum k 2 dp k si 2 2 si sum k sum k 2 dp k sum k 2 dp j sum j 2 2 si sum k sum j yk yj 2 si ...
HNOI2008 玩具裝箱TOY
題目描述 p教授要去看奧運,但是他捨不下他的玩具,於是他決定把所有的玩具運到北京。他使用自己的壓縮器進行壓縮,其可以將任意物品變成一堆,再放到一種特殊的一維容器中。p教授有編號為1 n的n件玩具,第i件玩具經過壓縮後變成一維長度為ci.為了方便整理,p教授要求在乙個一維容器中的玩具編號是連續的。同時...
HNOI2008 玩具裝箱TOY
這題可以說是斜率優化dp的模板題。首先,我們先推推它的dp式 f i min 這裡的c i 表示的是原來的c 1 i 的和 然後我們假設k我們可以將c i 再表示為c 1 i i,這樣就簡單很多了。改改dp式 f i min f j c i c j l 1 2 2我們用換元法,設x c j l 1,...