dp斜率優化

2022-02-25 03:40:56 字數 2517 閱讀 2185

前置知識:

凸包

斜率優化很玄學,憑空講怎麼也講不好,所以放例題。

[apio2014]序列分割

給你乙個長度為 \(n\) 的序列 \(a_1,a_2,...,a_n\)。你可以切 \(k\) 刀,每一刀可以把某一段序列切成兩段,然後獲得兩段和成績的收益。最後求最大收益和得到最大收益的切割方案。

資料範圍:\(2\le n\le 100000,1\le k\le\min\,1\le a_i\le 10000\)。

首先證明,切的順序不影響結果。設序列為連著的 \(a,b,c\) 三段。三段的和分別為 \(a,b,c\)。

如果先切開 \(a|b,c\) 再切開 \(a|b|c\),獲益為 \(a(b+c)+bc=ab+ac+bc\)。

如果先切開 \(a,b|c\) 再切開 \(a|b|c\),獲益為 \((a+b)c+ab=ac+bc+ab\)。

所以以此類推,切割的順序不影響最終收益大小。

然後開始 \(\texttt\),\(f_\) 表示前 \(i\) 個數切 \(j\) 刀的最大收益,\(s_i=\sum\limits^i_a_j\),則有狀態轉移方程:

\[f_=\max\+s_t(s_i-s_t)\}(0\le t

因為 \(f_\) 只由 \(f_\) 推得,所以可以滾動陣列 \(f\),令 \(f_j=f_\),\(g_j=f_\),那麼上式就變成:

\[f_i=\max\(0\le t

如果直接暴力跑一次 \(2\) 重迴圈的 \(\texttt\),\(\theta(n^2k)\) 會 \(\color}\),但你仔細觀察 \(g_t+s_t(s_i-s_t)\) 這個式子,如果有乙個 \(p(0\le p滿足

\[g_p+s_p(s_i-s_p)\ge g_t+s_t(s_i-s_t)

\]則推式可得:

\[(g_p-s_p^2)-(g_t-s_t^2)\ge s_t\cdot s_i-s_p\cdot s_i

\]\[\therefore\frac\ge s_i

\]令 \(slope=\frac\)

如果把 \((-s_p,g_p-s_p^2)\) 和 \((-s_t,g_t-s_t^2)\) 看作平面直角座標系中的兩個點,那麼 \(slope\) 就是這兩個點連邊的斜率。

因為 \(\texttt\) 迴圈 \(i=1\to n\) 時 \(s_i\) 是遞增的,而兩個點的 \(slope\) 又不是隨 \(s_i\) 變化的,所以可以維護乙個雙頭單調佇列,每次把 \(i\) 放到隊尾,佇列滿足:

從左到右數遞增。

從左到右相鄰兩個數所對應的點連邊的斜率遞減。

然後維護佇列並 \(\texttt\):

迴圈 \(j=1\to k\):

賦值滾動陣列 \(g=f\),清零 \(f\)。

清空佇列並在佇列中加入 \(0\)(相當於原點)。

迴圈 \(i=1\to n\):

把佇列頭相鄰兩個數 \(slope\le s_i\) 的踢掉。

取佇列頭 \(p\),\(f_i=g_p+s_p(s_i-s_p)\)。

因為最終要輸出方案,所以記錄索引 \(pro_=p\)。

把 \(i\) 看作點 \((-s_i,g_i-s_i^2)\),如果隊尾相鄰元素的 \(slope\ge i\) 和隊尾元素的 \(slope\),就把隊尾元素踢掉。

隊尾加入 \(i\)。

然後在單調佇列和斜率優化的加持下,因為維護佇列和迴圈 \(\texttt\) 的總時間複雜度為 \(\theta(n)\), 所以總的時間複雜度縮減為 \(\theta(nk)\)。於是蒟蒻逃脫了 \(\color}\) 的風險。

#include using namespace std;

/*,,

a(b+c)+bc=ab+ac+bc\-\greatitude

(a+b)c+ab=ac+bc+ab/-/

*/#define lng long long

const int n=1e5+10,k=210;

int n,k,a[n],q[n],p[n][k]; //n,k,ai,queue,方案路徑

lng f[n],g[n],sum[n]; //fi,gt,si

double funct(int x,int y)

int main()

} printf("%lld\n",f[n]); //輸出最終最大收益

for(int i=k,j=n;i>=1;i--)

printf("%d%c",j=p[j][i],"\n "[i>1]); //輸出切割方案。

return 0;

}

祝大家學習愉快!

斜率優化 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斜率優化

我們知道,有些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...