斜率優化dp筆記

2021-08-21 12:10:43 字數 1616 閱讀 7084

瞎扯:演算法真的是無止境,從暴力到dp原本以為很神奇了,沒想到還能優化dp,而且是把o(n^2)變成o(n),真是無****說。

引入:我們來分析這麼乙個問題,給你n個數,要你把他們分成連續的若干塊,

使得讓他們的每段和的平方加起來最小.正常我們會想到的就是o(n^2)的dp,方程就是:

dp[i] = min(dp[j]+(sum[i]-sum[j])^2); (1<=j讓我們看看試著怎麼去優化它。設(1<=kdp[j]+(sum[i]-sum[j])^2 < dp[k]+(sum[i]-sum[k])^2

移項合併同類項得dp[j]+sum[j]^2-dp[k]-sum[k]^2 < 2sum[i]*(sum[j]-sum[k])

令f[x] = dp[x] + sum[x]^2,原式變為(f[j]-f[k])/(sum[j]-sum[k])

左邊的就變成了斜率似的東西了,而右邊則是乙個常數。可以以f[j]為縱座標,sum[j]為橫座標在座標系上表示出來.

總結:就是將dp方程只與j有關的部分看成y,與i和j有關的部分把j那部分看成x

根據上面的分析得如果滿足上面的式子j會比k優,令g(k,j) = (f[j]-f[k])/(sum[j]-sum[k]),

如果有g(k,j) >= g(j,i),k= g(j,i) >= 2*sum[t]

那麼此時k是最優的,如果是2*sum[t]>=g(k,j) >= g(j,i),i是最優的,g(k,j) >= 2*sum[t]>=g(j,i)這種情況i,k都比j優,j就跟不用考慮了。

就像這個斜率遞增的下凸包:

反之j這個點還是有希望成為最優的,我們用乙個單調佇列來儲存這些點將要插入的點放在隊尾,在插入之前看當前隊尾元素j如果滿足上面的g(k,j) > g(j,i)條件,就將j刪除,直到不滿足為止將i插入.那麼佇列就滿足從頭到尾的g(a,b),g(b,c)...遞增.

如果g(a,b)<2*sum[i],說明b比a優,刪除隊首a,直到g(a,b)>=2*sum[i]為止,這就維護了最優點的選擇,就在隊首的那個.

如果g(k,j)g(k,j)時,j就比k要優了,此時k就會被去掉了。

因為每個點只會被加入一次,刪除一次,所以整個的操作就變成了o(n),就是這麼神奇。

同理如果是求最大值,就變成了上凸包,大小關係變了,原理是一樣的。

hdu 3507很好的練習題:

#include#include#include#include#include#define inf 0x3f3f3f3f

using namespace std;

const int mx = 5e5 + 10;

typedef long long ll;

int a[mx],n,m,dp[mx],sum[mx];

int que[mx],head,tail;

bool better(int x,int y,int i)

bool small(int x,int y,int z)

int main()

printf("%d\n",dp[n]);

} return 0;

}

學習筆記 斜率優化DP

作為數學渣,先複習一下已知兩點 x 1,y 1 x 2,y 2 怎麼求過兩點的一次函式的斜率.待定係數法代入 y kx b 有 x 1k b y 1 x 2k b y 2 兩式相減有 k frac 故事圍繞著 演算法競賽高階指南 的三一道例題展開 任務安排 1 假如我們啟動了乙個任務 l,r 那麼它...

斜率優化DP學習筆記

本文以luogup3195 玩具裝箱為例,我們很容易可以的出下面這個柿子 f i min 設 b i s i i j 為 f i 的最優決策點,則有 f i f j b i b j l 1 2 把只與 j 有關的放在左邊 f j b j 2 b j l 1 2 b i b j b i 2 l 1 2...

斜率優化 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 如果把右邊...