前置知識:
凸包斜率優化很玄學,憑空講怎麼也講不好,所以放例題。
[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...