# DP優化 --- ## Outlines * 前綴和優化 * 單調隊列優化 * 矩陣快速冪優化 * Aliens優化 * 分治優化 * 斜率優化 --- ## 前綴和優化 用來優化$dp_i =\sum_{l_i \leq j \leq r_i} w_j$這種轉移,$w_j$必須和$i$無關 ---- ### 例題 [CF-985E. Pencils and Boxes](https://codeforces.com/contest/985/problem/E) 有$N$支筆要放進盒子,每盒至少放$k$支,盒子數量不限,第$i$支長度$a_i$,同一個盒子裡最長和最短的筆相差不超過$d$,問能不能放完所有筆 $N \leq 5 \cdot 10^5$ ---- 縮短全距?先把長度排序後分割成一些區間 ---- 簡單的$O(N^2)$作法: $dp[i]$是一個bool,代表前$i$項能不能放完,轉移就枚舉最後一次取的數量 ```cpp= for (int j = 0; j < i; ++j) if (i - j >= k && a[i] - a[j + 1] <= d) dp[i] |= dp[j]; ``` ---- 因為已經排序好了,所以轉移的範圍是一段區間 那要怎麼維護區間OR? ---- 就用區間和就好了,把bool當成int處理,區間和$>0$代表有1,而區間和可以$O(1)$用前綴和的差得到 ---- 區間的右界是簡單的$i-k$,那左界怎麼求? 排好了當然能二分搜,總複雜度$O(NlogN)$ <!-- .element: class="fragment" data-fragment-index="1" --> 對於較大的$i$左界會遞增,所以可以雙指標 ~~,那其實區間和用雙指標就好了不用前綴和~~,但是因為sort,總複雜度還是$O(NlogN)$~~,所以砸資結就好了~~ <!-- .element: class="fragment" data-fragment-index="2" --> ---- ### 更多例題 [CF-479E. Riding in a Lift](https://codeforces.com/contest/479/problem/E) [CF-1188C. Array Beauty](https://codeforces.com/contest/1188/problem/C) [CF-1225E. Rock Is Push](https://codeforces.com/contest/1225/problem/E) --- ## 單調隊列優化 ---- ### 經典題 [滑動窗口極值](https://zerojudge.tw/ShowProblem?problemid=a146) 給一個長度$N$的陣列和$K$,請對每個長度$K$的區間分別輸出最大值和最小值 $N \leq 10^6$ ---- 由左掃到右,維護一個deque,裡面存當前看的區間內所有可能成為之後看的區間的答案的位置,剩下的值都不用管。那哪些值是可能的呢? ---- 以最大值為例,假設現在看到$[i,i+k)$,最大值是$a_j$(假設有多個找最右邊),那$j$一定在裡面。 ---- 其他比$a_j$小的值怎樣才有機會成為答案?因為窗口滑太右邊後就取不到$a_j$了,所以$max_{j < t < i + k}a_t$也有機會(還不知道$i+k$後面長怎樣),令他為$j_1$,為方便順便令$j_0=j$,還能繼續找出$j_2,j_3,...$,這些就是deque裡的數 ---- 觀察$j_0, j_1, ...$,會得到一些性質 * $j_0 < j_1 < ...$ * $a_{j_0} > a_{j_1} > ...$ * $\max\limits_{j_i < j' < j_{i+1}}a_j' \leq a_{j_{i+1}}$ 因為有單調性,所以稱為單調隊列 ---- 那來看跑到$i+1$時會發生什麼事,首先,最前面的元素可能會超出窗口而"過期",過期就直接pop掉。中間這些數字暫時不變。後面會有新掃到的元素要加進來,注意到他是最晚過期的,所以不管再小都有機會,因為還沒掃到的那些可能更小。 ---- 但是新元素不能直接push,因為多得到一些資訊後,先前有機會的可能就失敗了。如果deque中有一個$x$滿足$a_x \leq a_{i+k}$,那因為之後看的所有包含$x$的區間也包含$i+k$,所以$x$就沒機會了 ---- 前面提過這個deque有單調性,所以$\leq a_{i+k}$的是一段後綴,把這些元素全部pop掉之後才能塞$i+k$。顯然的,單調性依舊存在 ---- 此時$[i+1,i+k+1)$的極值會在哪呢?前面就提過了,最大值在最前面,直接取就好了 ---- 整個過程 1. pop前面過期的 2. pop後面太小的 3. push新的 4. 取front當答案 基本上單調隊列的步驟都是這樣 ---- 那來分析複雜度,push在每個位置進行一次,$O(N)$,那pop呢? 反正丟幾個進去最多就出來幾次,所以也是$O(N)$ <!-- .element: class="fragment" data-fragment-index="1" --> ---- ### 例題 [CF-372C. Watching Fireworks is Fun](https://codeforces.com/contest/372/problem/C) 你在數線上$[1,N]$中看煙火,有$M$個煙火,第$i$個會在時間$t_i$位置$a_i$綻放,此時若你在$x$,會獲得$b_i-|a_i-x|$的開心度。你可以任選起始位置,之後每秒可以往左右移動最多$d$,不能超出$[1,N]$,問總開心度的最大值 $N \leq 150000, M \leq 300,$煙火照時間先後排 ---- 定義$dp[i][j]$代表在位置$j$看完煙火$i$時的最大開心度,轉移式 $dp[i][j] = \max\limits_{|k-j| \leq d \cdot (t_i - t_{i-1})}dp[i-1][k] + b_i - |a_i - j|$ ---- 會發現枚舉$k$時唯一影響DP值的只有前一次的DP值,所以轉移其實就是問一個區間最大值再另外加上只和$i,j$有關的東西 ---- 而且這個區間是單調向右跑的,所以可以用單調隊列線性算好一個時刻的所有位置,然後重複$M$次就做完了,複雜度$O(NM)$ ---- 注意記憶體可能會爆炸,但可以用滾動壓掉空間複雜度 ---- ### 經典題 **多重背包** $N$種東西,重$w_i$、值$c_i$、共$m_i$個,裝進容量$W$的背包裡,求最大價值和 ---- $O(NWlogW)$講過了,這邊講一個$O(NW)$的做法 ---- 這是暴力枚舉第$i$種取幾個的轉移式 $dp[i][j] = \max\limits_{0 \leq k \leq m_i}dp[i-1][j-w_i \cdot k] + c_i \cdot k$ ---- 這是同一條式子 $dp[i][j] = \max\limits_{j-w_i \cdot m_i \leq t \leq j, t \equiv j(mod\ w_i)} dp[i-1][t] + c_i \cdot \frac j{w_i} - c_i \cdot \frac t{w_i}$ 盯著他看,假設把$t \equiv j(mod\ w_i)$拉出來會發生什麼事? ---- 他變滑窗了 ---- 處理$i$這一層的時候,先把重量依照$mod\ w_i$分類,轉移只會在同一類中發生,而且單看一類的話會是滑動窗口極值,所以可以$O(\frac W{w_i} \cdot w_i)$做完,乘上枚舉物品,複雜度$O(NW)$ ---- ### 更多例題 [CF-940E. Cashback](https://codeforces.com/contest/940/problem/E) [CF-1237D. Balanced Playlist](https://codeforces.com/contest/1237/problem/D) --- ## 矩陣快速冪優化 當你的DP維度連線性都會爆的時候用的,要滿足轉移是線性的,而且轉移的範圍不大 ---- ### 例題 [CSA-Partial Ladder Graph](https://csacademy.com/contest/archive/task/partial_ladder_graph/) 給$N$,問這張圖有多少種邊集刪掉後保持連通 ![](https://i.imgur.com/NokxHCf.png) $N \leq 10^{18}$ ---- 先想DP,由左而右做到$(i,n+i)$時,有兩種情況,一種是前面連通,一種是有兩塊,$i,n+i$不同塊,晚點再把他們連起來 ---- 新增的邊只有三條,狀態從兩種轉移到兩種,這麼少動手畫一畫就好了 $dp[i][0] = dp[i-1][0] + dp[i-1][1] \cdot 2$ $dp[i][1] = dp[i-1][0] + dp[i-1][1] \cdot 4$ ---- 但是線性跑到$10^{18}$會爆炸,考慮把轉移寫成矩陣 $\begin{equation}\begin{bmatrix}dp[i][0]\\dp[i][1]\end{bmatrix} = \begin{bmatrix}1\ \ 2\\1\ \ 4\end{bmatrix}\begin{bmatrix}dp[i-1][0]\\dp[i-1][1]\end{bmatrix}\end{equation}$ ---- 繼續寫 $\begin{equation}\begin{bmatrix}dp[i][0]\\dp[i][1]\end{bmatrix} = \begin{bmatrix}1\ \ 2\\1\ \ 4\end{bmatrix}\begin{bmatrix}dp[i-1][0]\\dp[i-1][1]\end{bmatrix} = \begin{bmatrix}1\ \ 2\\1\ \ 4\end{bmatrix}^2\begin{bmatrix}dp[i-2][0]\\dp[i-2][1]\end{bmatrix}\end{equation}$ ---- 最後 $\begin{equation}\begin{bmatrix}dp[i][0]\\dp[i][1]\end{bmatrix} = \begin{bmatrix}1\ \ 2\\1\ \ 4\end{bmatrix}^{i-1}\begin{bmatrix}dp[1][0]\\dp[1][1]\end{bmatrix}\end{equation}$ ---- 所以我們要求的東西變成這個矩陣的$N-1$次方。跟乘法快速冪一樣,矩陣也可以用快速冪,一種作法是求出該矩陣的$2^0, 2^1, ...$次方,然後根據$N-1$二進位中1出現的位置把對應的矩陣乘上去 ---- $\begin{equation}\begin{bmatrix}1\ \ 2\\1\ \ 4\end{bmatrix}^{2^i} = \begin{bmatrix}1\ \ 2\\1\ \ 4\end{bmatrix}^{2^{i-1}} \cdot \begin{bmatrix}1\ \ 2\\1\ \ 4\end{bmatrix}^{2^{i-1}}\end{equation}$ $\begin{equation}\begin{bmatrix}1\ \ 2\\1\ \ 4\end{bmatrix}^{100101_2} = \begin{bmatrix}1\ \ 2\\1\ \ 4\end{bmatrix}^{100000_2} \cdot \begin{bmatrix}1\ \ 2\\1\ \ 4\end{bmatrix}^{100_2} \cdot \begin{bmatrix}1\ \ 2\\1\ \ 4\end{bmatrix}^{1_2}\end{equation}$ ---- 所以就進行$O(logN)$次矩陣乘法就好了,$m\times m$矩陣的矩陣乘法可以用簡單的三層迴圈得到,$O(m^3)$,所以這題的複雜度是$O(2^3logN)$ ---- 諸如以下形式的都可以用矩陣快速冪解決,通常矩陣維度要在100以內 $f(i) =a_1f(i-1)+a_2f(i-2)+...+a_kf(i-k)+bi+c$ $f(i)=a\cdot f(i-1)+b\cdot g(i-1), g(i)=c\cdot f(i-1)+d\cdot g(i-1)$ ---- ### 更多例題 [CF-1117D. Magic Gems](https://codeforces.com/contest/1117/problem/D) [CSA-Bunny on Number Line](https://csacademy.com/contest/archive/task/bunny-on-number-line/) --- ## Aliens優化 也叫WQS二分搜,一種神奇的二分搜,通常題目長的像"在序列中找恰(至多)$k$個點,使得...最大(最小)" ---- ### 例題 [2017全國賽-P6. AI-666 賺多少](https://tioj.ck.tp.edu.tw/problems/2039) 你要在$N$個時間點內買賣一個東西,他在第$i$個時間的價格是$a_i$(買賣一樣),但你一次只能買一個,賣掉後才能再買,而且最多買賣$K$次,問最多能賺多少錢 $N \leq 2 \cdot 10^6$ ---- 官解是Greedy,但應該沒多少人用Greedy寫這題,而且我到現在還是不會 二維DP很直覺,但會爆 這題需要通靈 ---- 假設不管次數限制,很顯然的DP解是看現在在哪以及下一個動作是買或賣,然後算最大值。 ---- 我們可以在過程中順便DP最少要買賣幾次才有這個價值。假設很幸運次數沒爆,那可以直接輸出解了,但通常當然沒這麼幸運。 ---- 那我們要想個辦法逼他買賣少次一點。假設規定他每賣一次就要繳稅,次數是不是就會少一點了? ---- 但是這樣要怎麼知道他原本賺的錢? 別忘了我們可以算次數,把繳稅後的獲利加上稅金乘以次數就好了 <!-- .element: class="fragment" data-fragment-index="1" --> ---- 這邊還有一個很重要的觀察,因為繳稅只和次數有關,我們令$f(i)$代表原本買賣$i$次的最大獲利,$g(i)$代表繳稅時的,每次的稅金是$cost$,那下面的等式恆成立 $f(i)=g(i)+i \cdot cost$ ---- 也就是說,在固定次數時的策略是固定的,不受$cost$影響 ---- 那Aliens要怎麼利用這個$cost$?想像一下當$cost$很少時,是不是可以買很多次,但$cost$很多時,就會放棄交易 ---- 那就二分搜一下$cost$,當次數太多時就增加$cost$,太少時就減少$cost$,只要控制讓$k$次是最佳解,就可以用前面的等式反推我們要的答案了。這樣的總複雜度是$O(NlogC)$,會過 ---- 但其實還有很多問題,Aliens並沒有這麼方便 * 怎麼證明可以二分搜(有單調性) * 這樣只算恰$k$次,如果少次一點其實更好呢? * 一定找的到恰$k$次的$cost$嗎 ---- 接下來的部分我不會證明,可以自己感覺一下 ---- 假設把$(i, f(i))$畫在二維平面上,會是一個凹函數,也就是當次數遞增時,獲利會先增加後減少,且變化量($f(i)-f(i-1)$)遞減 ![](https://i.imgur.com/9smUIBK.png =40%x) ---- 不嚴謹理解,就是你一開始每多一次可能就會多出一次很好的買賣,但隨著次數用多了,好的用完,就只能多賺一點點,到最後甚至只剩虧本生意 ---- 總之如果是凹函數,就能重新理解一下二分搜在幹嘛了。其實我們就是在二分搜一個斜率,使得該斜率的直線和圖形切於$k,f(k)$ ![](https://i.imgur.com/c3JPgWT.png) ---- 偷個WiwiHo的優質GIF,圖中藍色是$f(x)$,紅色是$g(x)$,金色是極值位置 ![](https://i.imgur.com/VzEyIul.gif) ---- 假設我們已經理解Aliens的原理了,那來解決剩下的問題吧 * 這樣只算恰$k$次,如果少次一點其實更好呢? * 一定找的到恰$k$次的$cost$嗎 ---- 少於$k$次比較好怎麼解決?觀察圖形應該會發現此時最好的就是少於$k$次,所以跟一開始說的一樣,不帶cost跑一遍就好了 ---- **找不到恰$k$次怎麼辦?** 先想想什麼時候會發生 ---- ![](https://i.imgur.com/r1FJbcY.png =60%x) ---- 這樣搜到我們要的斜率時次數會太少(因為DP時Greedy最少次數),但是斜率再大又太多次。怎麼辦? ---- 再看仔細一點 ![](https://i.imgur.com/r1FJbcY.png =60%x) ---- 這個次數下$g(x)$的極值跟$g(k)$一樣!所以答案就是$max(g(x)) + cost \cdot k$ ---- 那這題就這樣結束了,這邊講幾個細節: * 二分搜的$l,r$要取到值域上下界,注意可能有負的,負數做`(a+b)/2`是向上取整,容易爛掉,建議`a+b>>1` * 如果值域有浮點數,就要搜到浮點數 * 剛才說找不到極值在$k$時用小於的最大數$x$取代,記得此時$cost$要加$k$倍不是$x$倍 ---- * 因為只是對斜率二分,所以凸函數也可以,注意二分搜方向 * 根據DP時Greedy最大或最小次數判斷找不到的時候取稍大還是稍小,不確定就都試試 * 通常是Aliens的題目都很容易看出來,也不會特別證明,就直接砸。但有些不是的可能會誤以為是,de到死都de不出來,建議生隨機測資驗或是想其他做法 ---- ### 例題 [CF-125E. MST Company](https://codeforces.com/contest/125/problem/E) 給一張圖,邊權都是正的,請找到權值和最小的邊集,恰包含k條1的臨邊,且能讓圖連通 ---- 顯然是MST 注意到那k條邊不會形成環,因此當選的子圖不是樹的時候一定能在環上找其他邊移除 ---- 恰k條邊?Aliens砸下去 ---- 讓每條1的臨邊邊權額外加上一個cost,二分搜cost,跑MST,使得有恰k條邊被選中。相同的,只需要在正整數上二分搜就好,如果找不到恰k條的cost,可能是這三種情況: 1. cost再大都取太多 2. cost再小都取太少 3. 某個cost會取太多,+1就變太少 ---- **1. cost再大都取太多** 如果1的臨邊已經比其他邊都大,代表這些邊是讓圖連通必須取的,因此無解 ---- **2. cost再小都取太少** 代表邊數根本不夠,無解,其實一開始就能判掉 ---- **3. 某個cost會取太多,+1就變太少** 就是正常Aliens的case,取最接近的去算答案 ---- ### 更多例題 [CSA-Or Problem](https://csacademy.com/contest/archive/task/or-problem) [TIOJ-1737 . [APIO '07] Backup](https://tioj.ck.tp.edu.tw/problems/1737) [TIOJ-1341 . [IOI 2007, Day 1] Aliens](https://tioj.ck.tp.edu.tw/problems/1341) --- ## 分治優化 處理轉移點單調又有離線代價的問題,透過分治減少不必要的枚舉 ---- 現在對於一些$i$,想計算$max\ f(i, j)$,那得到最佳解時的那個$j$稱為轉移點,記作$g(i)=argmax_j\ f(i, j)$。假設滿足$\forall i, g(i) \leq g(i+1)$,就稱為轉移點單調。 ---- 假設我在計算$max\ f(i, j)$時,必須知道$max\ f(i-1,j)$才能算,那就稱代價在線,反之,我用任何順序都可以時,稱代價離線 ---- 另外,要快速檢查轉移點的單調性可以用**Monge condition** > 給一個$n \times m$矩陣$B$,若$\forall 1 \leq i < n, 1 \leq j < m$都有 > $B[i][j] + B[i + 1][j + 1]$ > $\leq(\geq) B[i][j+1] + B[i+1][j]$ > ,則說他滿足convex(concave) Monge condition ---- > 若滿足convex(concave) Monge condition,則具有凸(凹)單調性 但是有單調性不一定滿足Monge condition 那分治優化到底是什麼? <!-- .element: class="fragment" data-fragment-index="1" --> ---- ### 例題 [CF-1601C. Optimal Insertion](https://codeforces.com/contest/1601/problem/C) 給你長度分別為$n,m$的陣列$a,b$,你要把$b$的元素都塞到$a$裡,其中$a$原本的元素的相對順序要固定,$b$可以亂插,求最後長度$n+m$的陣列最少有幾個逆序數對 $n,m \leq 10^6$ ---- 首先$a$的順序固定,可以先算裡面的逆序數對 ---- $b$的順序可變,那先sort看看 ---- 那來考慮某個$b_i$塞進去時和$a$產生的逆序數對,假設他塞在$a_j,a_{j+1}$之間,那就數前面比他大+後面比他小就好了 ---- 不難猜到對$b_i$來說插的位置單調,這邊證一下。假設$b_i, b_{i+1}$分別插在$a_j,a_j'$前面最好(一樣好挑最左),$j>j'$,設$a$中$[j',j)$有$l_1$個數$<b_i$、$l_2$個數$<b_{i+1}$、$r_1$個數$>b_i$、$r_2$個數$>b_{i+1}$,則有 $r_1 < l_1$ $l_2 \leq r_2$ $l_1 \leq l_2$ $r_2 \leq r_1$ 顯然矛盾 ---- 接著可以發現讓每個$b_i$都挑最好的時,他們會照順序,所以在$b$的元素間的逆序數對是0,也就是這樣會是最好的 ---- 現在可以來解釋分治優化了。一開始,我們直接暴力看$b_\frac m2$要放哪,$O(N)$掃就好,假設是$a_x$旁邊 $\forall i < \frac m2, b_i$會放在$[a_1,a_x]$ <!-- .element: class="fragment" data-fragment-index="1" --> $\forall i > \frac m2, b_i$會放在$[a_x,a_n]$ <!-- .element: class="fragment" data-fragment-index="1" --> ---- 意思是,我們接下來如果遞迴處理$\frac m2$的兩邊,左邊暴力跑的時候只要枚舉一部分的轉移點就好,右邊只要枚舉另一部份的轉移點就好,所以大概有一半的枚舉在這邊被省略。當遞迴下去時,又會繼續省略$\frac 14,\frac 18, ...$,最後的複雜度只需要$O(NlogN)$就好 ---- 複雜度可以看這張圖理解 ![](https://i.imgur.com/e9x3k8O.png) ---- ```cpp= void dc(int l, int r, int _l, int _r) { //處理[l,r), 轉移點[_l,_r) if (l >= r) return; int m = l + r >> 1; int best;//m的轉移點 //計算best //... dc(l, m, _l, best + 1); dc(m + 1, r, best, _r); } ``` ---- 這題要注意的是,當只考慮$[\_l,\_r)$的轉移點,暴力跑的時候就只會跑這邊,所以算出來的逆序數對數並不是全部的,所以利用分治優化找完全部的轉移點後,要再跑一次正常的逆序數對,這部分可以用分治或資結做到,總複雜度$O(NlogN)$ ---- 那如果遇到轉移點單調的問題,但是代價不能離線,要怎麼做?有個神奇的東西叫CDQ分治,總之就是分治的一種,可以花$log$的代價讓在線的東西變成一堆離線的問題,但這裡先不介紹。 ---- ### 更多例題 [CF-673E. Levels and Regions](https://codeforces.com/contest/673/problem/E) [CF-321E. Ciel and Gondolas](https://codeforces.com/contest/321/problem/E) [CF-868F. Yet Another Minimization Problem](https://codeforces.com/contest/868/problem/F) --- ## 斜率優化 處理轉移式是一堆斜直線的極值問題 ---- 斜率優化的轉移式通常長這樣 $dp_i = \max\limits_{j<i}(a_j \cdot x_i + b_i) + c_i$ 可以想像把一堆$y=ax+b$丟到平面上,然後問$x=x_i$和他們最高的交點 ---- 一般的斜率優化需要比較複雜的資料結構或演算法來處理,所以這邊只會講簡單的特例—斜率和詢問單調的斜率優化 ---- ### 例題 [TIOJ-1745 . [APIO '10] Commando](https://tioj.ck.tp.edu.tw/problems/1745) 有$N$個士兵,第$i$個有戰鬥力$x_i$,你要把他們分割成一些連續區間。假設一個區間的戰鬥力總和是$x=x_L+x_{L+1}+...+x_R$,那戰鬥力定義為$ax^2+bx+c$。詢問所有區間的戰鬥力總和最大是多少 $N \leq 10^6, a < 0, x_i > 0$ ---- 先列DP式 $dp_i = max_{j<i}(dp_j+a \cdot x(i,j)^2+b \cdot x(i,j) + c)$ ---- 看起來非常麻煩,先把$x(i,j)$用前綴和表示並展開 $\begin{align}dp_i = max_{j<i}(&dp_j + a \cdot pre_i^2 - 2a \cdot pre_i \cdot pre_j \\ + &a \cdot pre_j^2+ b \cdot pre_i - b \cdot pre_j + c)\end{align}$ ---- 整理一下 $\begin{align}dp_i = &a \cdot pre_i^2 + b \cdot pre_i + c\\+ &max_{j<i}(-2a \cdot pre_j \cdot pre_i \\ + &dp_j + a \cdot pre_j^2 - b \cdot pre_j)\end{align}$ 現在明顯是斜率優化了 <!-- .element: class="fragment" data-fragment-index="1" --> ---- 前面提過斜率和詢問要單調,轉移式中斜率為$-2a \cdot pre_j$,因為$x_i>0$,$pre_j$是遞增的,而$-2a$是正的常數,符合單調。詢問是$pre_i$,也單調。 ---- 那要怎麼處理呢?既然是要求一些$x$的最大值,那只要維護所有直線的下凸包就好了 ![](https://i.imgur.com/sefCDOa.png) ---- 要怎麼表達一個下凸包?就按照順序紀錄每條凸包上的直線就好了 ---- 那先想想要怎麼查詢某個$x$的最大值 ---- 前面提過詢問單調,也就是說所有在$x$左邊的直線之後都沒用了,所以可以一直看前兩條線的交點是不是在$x$左邊,是的話就pop第一條,否則代表最左邊那條有包含$x$,因此直接查那條直線在$x$的值就好了 ---- 接下來是修改,也就是插入一條直線 ---- 插入的會是當前斜率最大的直線,他顯然會在下凸包最右邊,但是在插入前,要檢查會不會有直線被淘汰掉,也就是原本在凸包上的區間被新的直線覆蓋 ---- 可以發現被覆蓋的會是一段後綴 ![](https://i.imgur.com/G2emCLH.png) ---- 所以就一直檢查新的和倒數第二條的交點,如果最後一條在那裡輸了,那他的右半會被新直線覆蓋,所以要pop掉,否則代表剩下的線都還在凸包上,此時再把新的直線放入最後面 ---- 其實整個操作就是單調隊列,所以複雜度也一樣是$O(N)$ ---- 單調的題目較少,這邊就不放了。非單調的斜率優化經典做法是維護動態凸包,也可以用~~怪科技~~李超線段樹輕鬆寫掉,如果硬要的話,還可以套CDQ分治強制當成單調的做,有興趣自己搜尋
{"metaMigratedAt":"2023-06-16T18:55:17.366Z","metaMigratedFrom":"Content","title":"DP優化","breaks":true,"contributors":"[{\"id\":\"bc9b0353-6035-4ee1-b41d-067c386529fd\",\"add\":15511,\"del\":2716}]"}
    797 views