DP優化

先說一下:今天說的都是求最大最小值的DP,等一下的max也可以是min

單調隊列優化

長相(通常):

dp[i]=maxj+k < i(g(i)+f(j))dp[i] = \max\limits_{j + k  <  i}( g(i) + f(j))

 dp[i]=g(i)+maxj+k < i f(j)dp[i] = g(i) + \max\limits_{j + k  <  i}  f(j)

其中kk固定

考慮

給長度為NN的序列AA和一個數字kk,求長度為N k+1N -  k + 1的序列BB,使得

Bi=maxj+k1<iAjB_i = \max\limits_{j+k-1 < i} A_j

Input: N=6, k=3

 A: 9 5 3 6 2 8

B: 9 6 6 8

有人會做ㄇ

這裡讓我偷一下

回來看:

dp[i]=g(i)+maxj+k < i f(j)dp[i] = g(i) + \max_{j + k  <  i}  f(j)

其中kk固定

根本跟剛剛一樣?
deque做到O(N)!

其實不只這樣?

1.k可以遞減,不用固定

2. 不一定是index距離小於一個東西

斜率優化

長相(通常):

dp[i]=maxj<i(g(i)+a(j)×f(i)+b(j))dp[i] = \max\limits_{j < i} (g(i) + a(j) \times f(i) + b(j))

 dp[i]=g(i)+maxj<i(a(j)×f(i)+b(j))dp[i] = g(i) + \max\limits_{j < i}( a(j) \times f(i) + b(j))

 

一樣轉換問題

請你支援兩種操作:

1.加入一條直線y=ai×x+biy = a_i \times x + b_i

2.詢問一個xx對應到的所有那些直線中y最大的值

我也不會QQ

例題是理解的試金石

狀態

dp[i]代表分好前i個人之後的最大值

轉移

dp[i]=maxj<i(dp[j]+a×(sisj)2+b×(sisj)+c)dp[i] = \max\limits_{j < i}( dp[j] + a \times (s_i - s_j)^2 + b \times (s_i-s_j) + c)

怎麼變成

 dp[i]=g(i)+maxj<ia(j)×f(i)+b(j)dp[i] = g(i) + \max_{j < i} a(j) \times f(i) + b(j)

 

dp[i]=maxj<i(dp[j]+a×(sisj)2+b×(sisj)+c)=a×si2+b×si+c+maxj<i((2a×sj)×si+(dp[j]+a×sj2b×sj))\begin{matrix} dp[i] &= & & \max\limits_{j < i}( dp[j] + a \times (s_i - s_j)^2 + b \times (s_i-s_j) + c) \\ &= & & a\times s_i^2 + b\times s_i + c \\ & &+ & \max\limits_{j < i}((-2a \times s_j) \times s_i + (dp[j] + a\times s_j^2 - b\times s_j)) \end{matrix}
\begin{matrix} dp[i] &= & & \max\limits_{j < i}( dp[j] + a \times (s_i - s_j)^2 + b \times (s_i-s_j) + c) \\ &= & & a\times s_i^2 + b\times s_i + c \\ & &+ & \max\limits_{j < i}((-2a \times s_j) \times s_i + (dp[j] + a\times s_j^2 - b\times s_j)) \end{matrix}

轉換成功!可是到底怎麼做?

注意這些直線的斜率是(2a×sj)(-2a \times s_j),因為原序列是正整數,所以斜率會遞增!而且我們每次都是要查sis_i,這東西也會遞增!

斜率、查詢遞增的斜率優化

用deque照斜率遞增維護直線

1

2

3

查詢

插入直線

O(N)
YA!

斜率不單調

用multiset往後殺往前(被)殺
直接當模板ㄅ

方法一

李超線段樹

方法二

二分搜

wqs

我也不太懂啦QQ

作法

二分搜一個mid,把每個白邊的權重都加上mid(也就是指選每個白邊的代價),然後做最小生成樹,若用太多白邊就增加代價,否則減少代價。最後答案就是最小生成樹權重減need*mid。

使用白邊的數量

最小生成樹權重

needneed

f(need)f(need)

等等,他為啥是凸的?

我就爛QQ

根據經驗
顯然
寫完之後AC
感覺
別人說

使用白邊的數量

最小生成樹權重

needneed

f(need)f(need)

???

minmin

f(min)f(min)

OK!

使用白邊的數量

最小生成樹權重

f(x)f(x)

f(x)xf(x)-x

f(x)2xf(x)-2x

f(x)+xf(x)+x

f(x)+2xf(x)+2x

need

f(need)f(need)

f(need)need×2f(need)-need\times2

YA!

aliens 優化

就是把wqs二分搜套到DP上

例題是理解的試金石

狀態

dp[i][j][0]dp[i][j][0]:考慮前ii天,交易了jj次,而現在手上沒有東西的最大價值

dp[i][j][1]dp[i][j][1]:考考慮前ii天,交易了jj次,而現在手上有東西的最大價值

轉移

dp[i][j][0]=max(dp[i1][j][0],dp[i1][j][1]+v[i])dp[i][j][0] = \max(dp[i-1][j][0],dp[i-1][j][1] +v[i])

dp[i][j][1]=max(dp[i1][j][1],dp[i1][j1][0]v[i])dp[i][j][1] = \max(dp[i-1][j][1],dp[i-1][j-1][0] -v[i])

凸性誰來救

我噁噁的code(不要學)

https://pastebin.com/0M770Lf2

關於aliens的一些事

1. 你覺得一題是aliens,不是因為他的函數是凸的(除非you mean wall),個人認為有兩個東西比較好看出:

(1)他限制了某個東西的次數

(2)你列出DP式,把不必要的東西去掉後,狀態還是多到就算轉移是O(1)也跑不完

關於aliens的一些事

2. 倘若那個凸函數的值域是整數,就不用小數二分搜

3. 有時候那個函數是不嚴格凸的,所以不一定二分搜的到剛好用了kk次的時候,這時候就讓你的dp在答案一樣的時候盡量用比較少次,再直接把二分搜所加上的權重ww拿去dp,然後你就輸出dp的答案wk-w*k就好了

4.二分搜的上下界自己搞清楚或是問@casperwang

現在有時間的話寫寫看這題

四邊形優化

溫馨提醒:為了延續蕭電的風格,就先暫時放下自己的強迫症好了

 -- by 忍不住想排版的03t

為什麼叫四邊形?

pD/qD DP

大家應該都知道這是甚麼鬼東西了吧

凸?

若對於任意的i<i,j<ji < i^′, j < j^′
如果F(j,i)F(j,i)F(j, i)\geq F(j^′, i) 成立的話,必可以保證F(j,i)F(j,i)F(j, i^′)\geq F(j^′, i^′)

這是什麼鬼

凸?

若對於任意的i<i,j<ji < i^′, j < j^′
如果F(j,i)F(j,i)F(j, i)\geq F(j^′, i) 成立的話,必可以保證F(j,i)F(j,i)F(j, i^′)\geq F(j^′, i^′)

多米諾效應:

我現在比你多,未來一定比你多

凹?

若對於任意的i<i,j<ji < i^′, j < j^′
如果F(j,i)F(j,i)F(j, i)\leq F(j^′, i) 成立的話,必可以保證F(j,i)F(j,i)F(j, i^′)\leq F(j^′, i^′)

應該懂了(?

小測驗

判斷以下函數是否有四邊形單調性

F(x,y)=xyF(x, y) = xy

F(x,y)=(xy)2F(x, y) = (x-y)^2

F(x,y)=sx+tyF(x, y) = s_x + t_y

s,ts, t 是遞增數列

F(x,y)=aA(x,y)+bB(x,y)F(x, y) = aA(x, y) + bB(x, y)

a,b0a, b \geq 0

A, B 有凹四邊形單調性

四邊形不等式(交叉與包含)

如果對於任何i<ij<ji < i^′ \leq j < j^′

都有F(j,i)+F(j,i)F(j,i)+F(j,i)F(j, i) + F(j^′, i^′)\leq F(j, i^′) + F(j^′, i)

則 F 滿足凸四邊形單調性。

舉一隅以一隅反

如果對於任何i<ij<ji < i^′ \leq j < j^′

都有F(j,i)+F(j,i)F(j,i)+F(j,i)F(j, i) + F(j^′, i^′)\geq F(j, i^′) + F(j^′, i)

則 F 滿足凹四邊形單調性。

還有

判斷以下函數是否有四邊形單調性

C 是正整數數列,K 是正整數

我也不知道答案

[HNOI 2008] 玩具裝箱

它也可以斜率優化

[POI 2011]Lightning Conductor

F(i,j)=F(i, j) =

反芻

四邊形不等式

凹跟凸有什麼用

四邊形單調性

2D/1D四邊形優化

長相(通常):

dp[i][j]=minikj{dp[i][k]+dp[k][j]+w(i,j)}dp[i][j] = \min\limits_{i\leq k\leq j}\{dp[i][k] + dp[k][j] + w(i, j)\}

從夾在裡面的東西轉移

尋找蘿莉第二彈

額,先別管題敘

算了還是看一下好了

這是建中校內賽題

尋找蘿莉第二彈

dp[l][r]=minlkr{dp[l][k]+dp[k][r]+sum(l,r)}dp[l][r]=\min\limits_{l≤k≤r}\{dp[l][k]+dp[k][r] + sum(l, r)\}

尋找蘿莉第二彈

dp[l][r]=minlkr{dp[l][k]+dp[k][r]+sum(l,r)}dp[l][r]=\min\limits_{l≤k≤r}\{dp[l][k]+dp[k][r] + sum(l, r)\}

凸??

好啦通常w凸dp就凸 QQ 然後這就凸凸的

重要定理

pi,jp_{i,j} 是dp[i][j] 在轉移時所找到的最佳轉移點,且dp 滿足凸四邊形不等式,則:
pi,j1pi,jpi+1,jp_{i,j−1} \leq p_{i,j} \leq p_{i+1, j}

打無限個星號 考翻了

2D/1D凸四邊形優化

dp[i][j]=minikj{dp[i][k]+dp[k][j]+w(i,j)}dp[i][j] = \min\limits_{i\leq k\leq j}\{dp[i][k] + dp[k][j] + w(i, j)\}

dp[i][j]=minpi,j1kpi+1,j{dp[i][k]+dp[k][j]+w(i,j)}dp[i][j] = \min\limits_{p_{i, j-1}\leq k\leq p_{i+1, j}}\{dp[i][k] + dp[k][j] + w(i, j)\}

紀錄好轉移來源

for(int len = 2; len <= n; len++){  // 枚舉區間長度 (i - j)
    for(int i = 1, r = len; j <= n; i++, j++){
        // 枚舉長度為 len 的所有區間
        dp[i][j] = INF;
        for (int k = p[i][j-1]; k <= p[i+1][j]; k++) {
            if (dp[i][j] > dp[i][k] + dp[k+1][j] + w(i, j)) {
            	// 更新 dp 陣列
            	dp[i][j] = dp[i][k] + dp[k+1][j] + w(i, j);
            	p[i][j] = k;  // 記錄(最小)轉移來源
            }
        }
    }
}

核心代碼

這題其實有很多種等價的題序,讓我們來看看吧!

其實也有O(nlogn)O(nlogn)的做法

1.石子合併
2.OBST

2D/1D凸四邊形優化

使用時機

1. DP式是2D/1D的

2. 滿足四邊形不等式

3. 至少w要凸

2D/1D凹沒有好性質

所以只能枚舉ii,讓dp狀態變成一維

用N次的1D/1D 解決

時間複雜度N2logNN^2 \log N

1D/1D四邊形優化

a.k.a. 決策單調性優化

長相(通常):

dp[i]=min0j<i{dp[j]+w(i,j)}dp[i] = \min\limits_{0\leq j < i}\{dp[j] + w(i, j)\}

dp[i]=min0j<i{w(i,j)}dp[i] = \min\limits_{0\leq j < i}\{w(i, j)\}

枚舉前面的點轉移

Lightning Conductor

a 是正整數序列,對於每個i求f[i]

Lightning Conductor

先假設i>ji > j 把絕對值拆掉

iji - j
i - j
<i< i
< i
f[i]=min1j<i{0,aj+ijai}f[i] = \min\limits_{1 \leq j < i}\{0, -\lceil a_j + \sqrt{i-j} - a_i\rceil \}
f[i] = \min\limits_{1 \leq j < i}\{0, -\lceil a_j + \sqrt{i-j} - a_i\rceil \}

Lightning Conductor

凸?

f[i]=min1j<i{0,aj+ijai}f[i] = \min\limits_{1 \leq j < i}\{0, -\lceil a_j + \sqrt{i-j} - a_i\rceil \}
f[i] = \min\limits_{1 \leq j < i}\{0, -\lceil a_j + \sqrt{i-j} - a_i\rceil \}

Lightning Conductor

證明四邊形不等式

w(a,d)+w(b,c)w(a,c)+w(b,d)w(a, d) + w(b, c) \leq w(a, c) + w(b, d)

兩邊消掉一些東西

da+cbca+db\sqrt{d - a} + \sqrt{c - b} \geq \sqrt{c - a} + \sqrt{d - b}

兩邊平方,排序不等式

bd+acbc+dabd + ac \geq bc + da

f[i]=min1j<i{0,aj+ijai}f[i] = \min\limits_{1 \leq j < i}\{0, -\lceil a_j + \sqrt{i-j} - a_i\rceil \}
f[i] = \min\limits_{1 \leq j < i}\{0, -\lceil a_j + \sqrt{i-j} - a_i\rceil \}

Lightning Conductor

有單調性了 XD

多米諾效應:

我現在比你差,未來一定比你差

f[i]=min1j<i{0,aj+ijai}f[i] = \min\limits_{1 \leq j < i}\{0, -\lceil a_j + \sqrt{i-j} - a_i\rceil \}
f[i] = \min\limits_{1 \leq j < i}\{0, -\lceil a_j + \sqrt{i-j} - a_i\rceil \}

1D/1D凸四邊形優化

struct seg{int p,l,r;};
deque<seg> deq;
void solve() {
    deq.push_back(seg{0,1,n});
    for(int i=1; i<n; i++) {
        // 計算dp[i]
        while(deq.front().r <= i) deq.pop_front();
        dp[i] = f(deq.front().p, i);
        // 更新以 i 作為轉移來源的區間
        while(deq.size() && f(i, deq.back().l) < f(deq.back().p, deq.back().l))
            deq.pop_back();
        seg new_seg = seg{i, i+1, n};
        if(deq.size()) { // 有可能全部被 pop 掉
            int c = binary_search(deq.back().p, i);
            // c 是滿足 f(i, k) < f(deq.back().i, k) 的最小 k
            deq.back().r = new_seg.l = c;
        }
        if(new_seg.l < n) deq.push_back(new_seg);
    }
}

核心代碼

1D/1D凸四邊形優化

使用時機

1. DP式是1D/1D的

2. 滿足四邊形單調性

3. 至少w要凸

1D/1D的也可以是凹

可是好像沒什麼必要用QQ

分治優化

同一題

a 是正整數序列,對於每個i求f[i]

分治做法

哈哈 其實這題有輕鬆的做法

solve(L, R, ll, rr)

計算區間[L, R)且轉移點限制在[ll, rr)內的答案

分治做法

solve(L, R, ll, rr)

暴力算mid的答案與轉移來源p

 

ㄈsolve(l,mid-1,ll,dim)分治解決solve(l, mid, ll, p) 和

solve(mid+1, r, p, rr)即可

核心代碼

void solve(int l,int r,int ll,int rr) {
    if(l > r) return;
    int mid = (l+r)/2, p = 0;
    for(int i=ll; i<=min(mid,rr); i++) {
        if(num[i] - num[mid] + sqrt(abs(mid-i)) > dp[mid]) {
            dp[mid] = num[i] - num[mid] + sqrt(abs(mid-i));
            p = i;
        }
    }
    solve(l, mid, ll, p), solve(mid+1, r, p, rr);
}

注意:dp数组要开成 doubledouble ,决策时也要用 doubledouble ,只有输出时才取整,这样才是符合题意的,不能过程中直接取整=。=(不要问我为什么要说这个)

-- 崩潰的大陸人

分治優化使用時機

1. 還是要有決策單調性

2. 不限定計算順序 (轉移式不含dp項)

一堆題目

狀態

dp[i][0]dp[i][0]:考慮前ii天,第i天不吃拉麵的最高分

dp[i][1]dp[i][1]:考慮前ii天,第i天吃拉麵的最高分

轉移

dp[i][0]=max(dp[i1][0],dp[i1][1])dp[i][0] = \max(dp[i-1][0],dp[i-1][1])

dp[i][1]=maxikj<i(dp[j][0]+S[i]S[j])dp[i][1] = \max\limits_{i-k \leq j < i}(dp[j][0] + S[i] - S[j])

1D/1D四邊形優化經典題

ans[i]=maxj<i{A(j,i)}ans[i] = \max\limits_{j < i} \{A(j, i)\}

A(j,i)A(j, i)是以第j條線為下界,第i條橫線為下界的最大矩形面積

可以證明轉移點遞增

再用1D/1D凸或分治解決

倒過來考慮


狀態
dp[i]dp[i]代表放完前ii個東西後的最大值

轉移

dp[i]=maxikj<i(dp[j]+Sj(ij)2)dp[i] = \max\limits_{i-k\leq j < i}(dp[j]+S_j - (i-j)^2)
 

小心處理過期

狀態
dp[i]dp[i]表示買進第ii台機器時,擁有的最多錢數

轉移

dp[i]=maxj<i,dp[j]0(dp[j]+(DiDj)2Gj+RjPi)dp[i] = \max\limits_{j < i,dp[j]\geq0}(dp[j]+(D_i - D_j)^2*G_j+R_j-Pi)

狀態
dp[i][j]dp[i][j]表示考慮前ii個房子,蓋了jj座郵局的最短距離和
w[i][j]w[i][j]表示在第ii個房子和第jj個房子中,只蓋一座郵局的最短距離和

轉移
dp[i][j]=mink<i(dp[k][j1]+w[k+1][i])dp[i][j] = \min\limits_{k < i}(dp[k][j-1]+w[k+1][i])

狀態

dp[i][j]dp[i][j]表示考慮前ii個洞,放入前jj隻老鼠

w[i][j]w[i][j]代表前jj隻老鼠都跑到第ii個洞所需的花費

轉移

dp[i][j]=mink+c[i]>j(dp[i1][k]+w[i][j]w[i][k+1])dp[i][j] = \min\limits_{k+c[i] > j}(dp[i-1][k] + w[i][j] - w[i][k+1])

狀態

dp[i][j]dp[i][j]表示考慮前ii個洞,放入前jj隻老鼠

w[i][j]w[i][j]代表前jj隻老鼠都跑到第ii個洞所需的花費

轉移

dp[j]=mink+c>j(dp1[k]+w[j]w[k+1])dp[j] = \min\limits_{k+c > j}(dp1[k] + w[j] - w[k+1])

狀態:

dp[i][j][k]dp[i][j][k]代表考慮前ii隻pokemon,用了jj個紅球、kk個黑球的隻數最大期望值

轉移:

dp[i][j][k]=max(dp[i1][j][k],dp[i1][j1][k]+pi,dp[i1][j][k1]+ui,dp[i1][j1][k1]+ui+pipi×ui)dp[i][j][k] = \max(dp[i-1][j][k],dp[i-1][j-1][k] + p_i,dp[i-1][j][k-1] + u_i,dp[i-1][j-1][k-1] + u_i+p_i-p_i\times u_i)

狀態:

dp[i][j][0]dp[i][j][0]代表前ii組,取了jj組,第ii組不取

dp[i][j][1]dp[i][j][1]代表前ii組,取了jj組,第ii組要取

轉移:

dp[i][j][0]=min(dp[i1][j][1],dp[i1][j][0])dp[i][j][0] = \min(dp[i-1][j][1],dp[i-1][j][0])

dp[i][j][1]=dp[i1][j1][0]+1dp[i][j][1] = dp[i-1][j-1][0] + 1

狀態
dp[i][j]dp[i][j]表示考慮前ii個房子,蓋了jj座郵局的最短距離和
w[i][j]w[i][j]表示在第ii個房子和第jj個房子中,只蓋一座郵局的最短距離和

轉移
dp[i][j]=mink<j(dp[k][j1]+w[k+1][j])dp[i][j] = \min\limits_{k < j}(dp[k][j-1]+w[k+1][j])

狀態
dp[i][j]dp[i][j]表示考慮前ii個房子,蓋了jj座郵局的最短距離和
w[i][j]w[i][j]表示在第ii個房子和第jj個房子中,只蓋一座郵局的最短距離和

轉移
dp[i]=mink<i(dp[k]+w[k+1][i]+cost)dp[i] = \min\limits_{k < i}(dp[k]+w[k+1][i] + cost)

DP優化

By Zi-Hong Xiao

DP優化

  • 1,274