r
題意:把n分成任意段(每段中連續),每一段代價(∑ ci ) +m 求總的最小代價
i=l作為提醒自己的經驗題,即使再水也要記住坑點(其實是自己被坑的地方- -)
斜率優化裸題- -
首先定義dp[i]表示把前i個處理好的最小代價
dp[i]=min
一看這個轉移就是n^2的,我們來搞成o(n)的。
h[i]=m+sum[i]^2,g[j]=sum[j]^2
->> dp[i]=dp[j]+h[i]+g[j]-2sum[i]sum[j]
考慮對於乙個j1dp[j1]+g[j1]-2sum[i]sum[j1]>dp[j2]+g[j2]-2sum[i]sum[j2]
令y=dp[j]+g[j]
(y[j1]-y[j2])/(sum[j1]-sum[j2])<2sum[i] (sum[j1]然後就搞成了斜率
令左邊為t(j1,j2),t(j1,j2)<2sum[i]時,j2更優
對於x我們要維護的就是t(x,y)>2sum[i]這一部分
我們考慮對於t(j1,j2),t(j2,j3)應該怎麼維護:
對於t(j1,j2)>2sum[i]時,j1更優,j2不是最優;
對於t(j1,j2)<2sum[i]時,如果t(j2,j3)所以t(j1,j2)>t(j2,j3)的時候,j2一定不是最優的。
所以我們要維護t(j1,j2)
綜上,我們要維護2sum[i]此時j1最優。
就維護乙個t>sum[i]的序列並且遞增
好了,接下來說明坑點:
以前寫toy那道題,我直接double求斜率,然而這一次不適用,我才發現直接求double斜率會掛精度!!!!
所以我們先看成維護斜率,在判斷的時候把分母乘到右邊去,用乘法代替除法,大概估算用long long不會超!
#include#include#include#include#include#include#include#define ll long long
using namespace std;
const ll maxn=500000+20;
ll dp[maxn];//dp[i] means min cost of [1,i]
/*dp[i]=min
dp[i]=dp[j]+sum[i]^2+sum[j]^2-2sum[i]sum[j]+m
h[i]=sum[i]^2+m;
g[j]=sum[j]^2
dp[i]=dp[j]+h[i]+g[j]-2sum[i]sum[j]
對於j1dp[j2]+g[j2]-2sum[i]sum[j2]
y[j]=dp[j]+g[j]
(y[j1]-y[j2]) /(sum[j1]-sum[j2])<2sum[i]
t(j1,j2)表示(j12sum[i]表示j1更優
ifx2sum[i]
考慮t(j1,j2)>2sum[i],j1更優
sum[i]增大,要滿足這個條件,t()也應該遞增
t(j1,j2)>2sum[i],j1更優
t(j1,j2)<2sum[i]時,如果t(j2,j3)=2*sum[i]*down(q[head],q[head+1]))head++;
ll j=q[head];
dp[i]=dp[j]+m+(sum[i]-sum[j])*(sum[i]-sum[j]);
while(head=up(q[tail],i)*down(q[tail-1],q[tail]))tail--;
q[++tail]=i;
} printf("%i64d\n",dp[n]);
} return 0;
}
hdu 3507 斜率優化
我的第一道斜率優化。就這道題而言,寫出原始的方程 dp i min o n 2 的複雜度肯定超時,要麼優化轉移,要麼重寫方程。斜率優化的思想就是減少不必要的列舉 即不列舉肯定不會成為決策點的j 我們考慮兩個位置p 選擇q比選擇p優 當且僅當 dp q sum i sum q 2 m dp p sum...
hdu3507斜率優化dp
這題 n可能取500000,o n 2 就會超時吧,所有只能優化。注意到這題的動態規劃方程 dp i max dp j sum i sum j 2 m 化簡下得 dp i max dp j sum i 2 sum j 2 2 sum i sum j 無法直接用單調佇列優化,i和j不能分開。假設j比k...
hdu3507 動態規劃 斜率優化
解題報告題目 題目大意 將序列 c n 分成若干段,每段的值為 c i 2 m.求序列的最小值。演算法 動態規劃 斜率優化 思路 看到題目以為數字和亂序,就沒想是動歸而是數論。因為所求的值與段數無關,因此設定dp方程時,不需要為段數設定狀態。設 dp i 表示前i段的最小值 則有 dp i min ...