斜率優化 DP

2021-07-02 01:09:54 字數 1716 閱讀 8568

我們知道,有些dp方程可以轉化成dp[i]=f[j]+x[i]的形式,其中f[j]中儲存了只與j相關的量。這樣的dp方程我們可以用單調佇列進行優化,從而使得o(n^2)的複雜度降到o(n)。

可是並不是所有的方程都可以轉化成上面的形式,舉個例子:dp[i]=dp[j]+(x[i]-x[j])*(x[i]-x[j])。如果把右邊的乘法化開的話,會得到x[i]*x[j]的項。這就沒辦法使得f[j]裡只存在於j相關的量了。於是上面的單調佇列優化方法就不好使了。

這裡學習一種新的優化方法,叫做斜率優化,其實和凸包差不多,下面會解釋。

舉例子說明是最好的!hdu 3507,很適合的乙個入門題。

大概題意就是要輸出n個數字a[n],輸出的時候可以連續連續的輸出,每連續輸出一串,它的費用是 「這串數字和的平方加上乙個常數m」。

我們設dp[i]表示輸出到i的時候最少的花費,sum[i]表示從a[1]到a[i]的數字和。於是方程就是:

dp[i]=dp[j]+m+(sum[i]-sum[j])^2;

很顯然這個是乙個二維的。題目的數字有500000個,不用試了,二維鐵定超時了。那我們就來試試斜率優化吧,看看是如何做到從o(n^2)複雜度降到o(n)的。

分析:我們假設k兩邊移項一下,得到:(dp[j]+num[j]^2-(dp[k]+num[k]^2))/(2*(num[j]-num[k]))那麼不就是yj-yk/xj-xk那麼yj-yk/xj-xk

關鍵的來了:現在從左到右,還是設k我們假設g[i,j]如果g[i,j]>=sum[i],那麼j點此時是比i點要更優,但是同時g[j,k]>g[i,j]>sum[i]。這說明還有k點會比j點更優,同樣排除j點。

排除多餘的點,這便是一種優化!

接下來看看如何找最優解。

設k由於我們排除了g[i,j]

這樣,從左到右,斜率之間就是單調遞減的了。當我們的最優解取得在j點的時候,那麼k點不可能再取得比j點更優的解了,於是k點也可以排除。換句話說,j點之前的點全部不可能再比j點更優了,可以全部從解集中排除。

於是對於這題我們對於斜率優化做法可以總結如下:

1,用乙個單調佇列來維護解集。

2,假設佇列中從頭到尾已經有元素a b c。那麼當d要入隊的時候,我們維護佇列的上凸性質,即如果g[d,c]=g[x,y]為止,並將d點加入在該位置中。

3,求解時候,從隊頭開始,如果已有元素a b c,當i點要求解時,如果g[b,a]

1 #include2 #include

3using

namespace

std;45

int dp[500005];6

int q[500005];7

int sum[500005];8

inthead,tail,n,m;910

int getdp(int i,int

j)11

1415

int getup(int j,int k) //

yj-yk的部分

1619

20int getdown(int j,int k) //

xj-xk的部分

2124

25int

main()

2647 printf("

%d\n

",dp[n]);48}

49return0;

50 }

dp斜率優化

我們知道,有些dp方程可以轉化成dp i f j x i 的形式,其中f j 中儲存了只與j相關的量。這樣的dp方程我們可以用單調佇列進行優化,從而使得o n 2 的複雜度降到o n 可是並不是所有的方程都可以轉化成上面的形式,舉個例子 dp i dp j x i x j x i x j 如果把右邊...

斜率優化DP

斜率優化主要解決的是轉移方程中存在乙個同時與i和j有關的部分時的優化問題 dp i min dp j a i b j 0 include using namespace std typedef long long ll const int maxn 1e5 5 ll a maxn b maxn dp...

dp斜率優化

前置知識 凸包 斜率優化很玄學,憑空講怎麼也講不好,所以放例題。apio2014 序列分割 給你乙個長度為 n 的序列 a 1,a 2,a n 你可以切 k 刀,每一刀可以把某一段序列切成兩段,然後獲得兩段和成績的收益。最後求最大收益和得到最大收益的切割方案。資料範圍 2 le n le 10000...