【題意】
給出n條連續線段,每條線段都有長度為x[i],我們可以把連續若干條線段連在一起,變成乙個組合,兩條線段如果相連,就要在兩條線段中間新增乙個長度為1的格仔(如果沒有相連就不用新增),假如我們現在選擇把第i條到第j條線段之間的所有線段變成一組合的話,這個組合的總長度就為:x[i]+x[i+1]+x[i+2]+x[i+3]+...+x[j]+j-i,現在給出乙個常數l,假設當前選擇的組合的長度為s,那麼這個組合就為我們產生了(s-l)^2的費用,求出把n條線段分成若干組合所需要的最小費用,單獨的線段可以成為乙個組合
【輸入檔案】
第一行兩個整數,分別為n和l。
下來n個數字xi,按編號從小到大輸入每個物品的容量。
1<=n<=50000,1<=l,xi<=10^7
【輸出檔案】
乙個整數,總花費的最小值。
【樣例輸入】
5 43 4 2 1 4
【樣例輸出】
1斜率優化其實就是乙個用來優化dp的演算法,但必須當dp方程具有單調性的時候才能使用
下來我們用例題來說明斜率優化
f[i]表示1~i的最小花費。
f[i]=min(f[j]+(sum[i]-sum[j]+i-(j+1)-l)^2) (j
首先我們先來證明決策單調性
假設j1
即要滿足:f[j2]+(s[i]-s[j2]-l)^2
則對於i後的所有狀態t,是否j2也不比就j1差?(術語:證明決策單調性)
即f[j2]+(s[t]-s[j2]-l)^2 < f[j1]+(s[t]-s[j1]-l)^2
容易理解s[t]=s[i]+v
所以得到(1)不等式:f[j2]+(s[i]-s[j2]-l+v)^2
因為已知(2)不等式:f[j2]+(s[i]-s[j2]-l)^2
所以化簡(1)不等式:把s[i]-s[j2]-l看成乙個整體,v看成乙個整體,得到:
f[j2]+(s[i]-s[j2]-l)^2+2*v*(s[i]-s[j2]-l)+v^2
比較(2)不等式:
左邊多了一部分:2*v*(s[i]-s[j2]-l)+v^2
右邊多了一部分:2*v*(s[i]-s[j1]-l)+v^2
所以我們只需要證:
2*v*(s[i]-s[j2]-l)+v^2<=2*v*(s[i]-s[j1]-l)+v^2
即:(s[i]-s[j2]-l)<=(s[i]-s[j1]-l)
即: -s[j2] <= -s[j1]
即:s[j1]
總結:對於當前i:j2比j1好,那麼對於t(i
所以當前i選擇j2,淘汰j1,以後的t也不會在j2存在的時候選擇j1
所以i的時候就可以永久淘汰j1
然後來求斜率方程
因為f[j2]+(s[i]-s[j2]-l)^2<=f[j1]+(s[i]-s[j1]-l)^2
展開:f[j2]+(s[i]-l)^2-2*(s[i]-l)*s[j2]+s[j2]^2<=f[j1]+(s[i]-l)^2-2*(s[i]-l)*s[j1]+s[j1]^2
即f[j2]-2*(s[i]-l)*s[j2]+s[j2]^2<=f[j1]-2*(s[i]-l)*s[j1]+s[j1]^2
即f[j2]+s[j2]^2-2*(s[i]-l)*s[j2]<=f[j1]+s[j1]^2-2*(s[i]-l)*s[j1]
即[(f[j2]+s[j2]^2)-(f[j1]+s[j1]^2)]<=2*(s[i]-l)*s[j2]-2*(s[i]-l)*s[j1]
即[(f[j2]+s[j2]^2)-(f[j1]+s[j1]^2)]/(s[j2]-s[j1])<=2*(s[i]-l)
對於j來說:
製造的點座標
y=f[j]+s[j]^2
x=s[j]
我們用佇列list在存有意義的決策點,list中相鄰兩點的斜率遞增(佇列中的點形成乙個下凸殼),而且都大於2*(s[i]-l),那麼佇列頭對於i來說就是最優決策點
加入決策i時,令隊尾為list[tail],前乙個為list[tail-1]
斜率函式slop(點1,點2)
滿足:slop(list[tail-1],list[tail])>slop(list[tail],i)時,
那麼隊尾list[tail]在三者(list[tail-1],list[tail],i)對於未來的tail絕對不會是最優的策略,所以將其彈出tail--
最後遇到了:slop(list[tail-1],list[tail])
然後f[n]就是答案了
#include#include#include
#include
using
namespace
std;
typedef
long
long
ll;ll a[
51000],s[51000],f[51000
];/*
f[i]=min(f[j]+(sum[i]-sum[j]+i-j-1-l)^2)
f[i]=min(f[j]+(s[i]-s[j]-l)^2)
f[j2]+(s[i]-s[j2]-l)^2<=f[j1]+(s[i]-s[j1]-l)^2
f[j2]+(s[i]-l)^2-2*s[j2]*(s[i]-l)+s[j2]^2<=f[j1]+(s[i]-l)^2-2*s[j1]*(s[i]-l)+s[j1]^2
f[j2]+s[j2]^2-2*s[j2]*(s[i]-l)<=f[j1]+s[j1]^2-2*s[j1]*(s[i]-l)
f[j2]-f[j1]+s[j2]^2-s[j1]^2<=2*s[j2]*(s[i]-l)-2*s[j1]*(s[i]-l)
f[j2]-f[j1]+s[j2]^2-s[j1]^2<=2*s[j2]*(s[i]-l)-2*s[j1]*(s[i]-l)
(f[j2]-f[j1]+s[j2]^2-s[j1]^2)/(s[j2]-s[j1])<=2*(s[i]-l)
*/double slop(int j1,int
j2)int list[51000];int
head,tail;
intmain()
printf(
"%lld\n
",f[n]);
return0;
}
演算法 動態規劃之斜率優化
斜率優化通常使用單調佇列輔助進行實現,用於優化 dp 的時間複雜度。使用單調佇列優化 dp 通常可以解決型如 dp i min f j g i 的狀態轉移方程。其中 f i 是只關於 i 的函式,g j 是只關於 j 的函式。樸素的解決方法是在第二層迴圈中列舉 j 來實現最小值,時間複雜度為 o n...
Dp優化 斜率優化
該模板的ai要具有單調性,也就是sum陣列 若沒有單調性,加個二分即可 我的一篇題解,很詳細 1 寫出狀態轉移方程 2 按照斜率優化的式子推導出式子 3 代入模板即可。include include using namespace std typedef long long ll const int...
演算法導論 快速排序優化演算法!
常見快速排序 時間複雜度最好情況下o nlgn 最壞情況o n2 快速排序是基於分治模式的 分解 陣列a p.r 被劃分成兩個 可能空 子陣列a p.q 1 和a q 1.r 使得a p.q 1 中的每個元素都小於等於a q 而且,小於等於a q 1.r 中的元素。下 標q 也在返個劃分過程中迕行計...