DP優化
先說一下:今天說的都是求最大最小值的DP,等一下的max也可以是min
單調隊列優化
長相(通常):
dp[i]=j+k < imax(g(i)+f(j))
dp[i]=g(i)+j+k < imax f(j)
其中k固定
考慮
給長度為N的序列A和一個數字k,求長度為N− k+1的序列B,使得
Bi=j+k−1<imaxAj
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)
其中k固定
根本跟剛剛一樣?
deque做到O(N)!
其實不只這樣?
1.k可以遞減,不用固定
2. 不一定是index距離小於一個東西
斜率優化
長相(通常):
dp[i]=j<imax(g(i)+a(j)×f(i)+b(j))
dp[i]=g(i)+j<imax(a(j)×f(i)+b(j))
一樣轉換問題
請你支援兩種操作:
1.加入一條直線y=ai×x+bi
2.詢問一個x對應到的所有那些直線中y最大的值
我也不會QQ
例題是理解的試金石
狀態
dp[i]代表分好前i個人之後的最大值
轉移
dp[i]=j<imax(dp[j]+a×(si−sj)2+b×(si−sj)+c)
怎麼變成
dp[i]=g(i)+maxj<ia(j)×f(i)+b(j)
轉換成功!可是到底怎麼做?
注意這些直線的斜率是(−2a×sj),因為原序列是正整數,所以斜率會遞增!而且我們每次都是要查si,這東西也會遞增!
斜率、查詢遞增的斜率優化
用deque照斜率遞增維護直線
1
2
3
查詢
插入直線
O(N)
YA!
斜率不單調
用multiset往後殺往前(被)殺
直接當模板ㄅ
方法一
李超線段樹
方法二
二分搜
wqs
我也不太懂啦QQ
作法
二分搜一個mid,把每個白邊的權重都加上mid(也就是指選每個白邊的代價),然後做最小生成樹,若用太多白邊就增加代價,否則減少代價。最後答案就是最小生成樹權重減need*mid。
使用白邊的數量
最小生成樹權重

need
f(need)
等等,他為啥是凸的?
我就爛QQ
根據經驗
顯然
寫完之後AC
感覺
別人說
使用白邊的數量
最小生成樹權重

need
f(need)
???
min
f(min)
OK!
使用白邊的數量
最小生成樹權重

f(x)
f(x)−x
f(x)−2x
f(x)+x
f(x)+2x
need
f(need)
f(need)−need×2
YA!
aliens 優化
就是把wqs二分搜套到DP上
例題是理解的試金石
狀態
dp[i][j][0]:考慮前i天,交易了j次,而現在手上沒有東西的最大價值
dp[i][j][1]:考考慮前i天,交易了j次,而現在手上有東西的最大價值
轉移
dp[i][j][0]=max(dp[i−1][j][0],dp[i−1][j][1]+v[i])
dp[i][j][1]=max(dp[i−1][j][1],dp[i−1][j−1][0]−v[i])
凸性誰來救
我噁噁的code(不要學)
關於aliens的一些事
1. 你覺得一題是aliens,不是因為他的函數是凸的(除非you mean wall),個人認為有兩個東西比較好看出:
(1)他限制了某個東西的次數
(2)你列出DP式,把不必要的東西去掉後,狀態還是多到就算轉移是O(1)也跑不完
關於aliens的一些事
2. 倘若那個凸函數的值域是整數,就不用小數二分搜
3. 有時候那個函數是不嚴格凸的,所以不一定二分搜的到剛好用了k次的時候,這時候就讓你的dp在答案一樣的時候盡量用比較少次,再直接把二分搜所加上的權重w拿去dp,然後你就輸出dp的答案−w∗k就好了
4.二分搜的上下界自己搞清楚或是問@casperwang
現在有時間的話寫寫看這題
四邊形優化
溫馨提醒:為了延續蕭電的風格,就先暫時放下自己的強迫症好了
-- by 忍不住想排版的03t

為什麼叫四邊形?
pD/qD DP
大家應該都知道這是甚麼鬼東西了吧
凸?
若對於任意的i<i′,j<j′:
如果F(j,i)≥F(j′,i) 成立的話,必可以保證F(j,i′)≥F(j′,i′)。
這是什麼鬼
凸?
若對於任意的i<i′,j<j′:
如果F(j,i)≥F(j′,i) 成立的話,必可以保證F(j,i′)≥F(j′,i′)。
多米諾效應:
我現在比你多,未來一定比你多

凹?
若對於任意的i<i′,j<j′:
如果F(j,i)≤F(j′,i) 成立的話,必可以保證F(j,i′)≤F(j′,i′)。
應該懂了(?
小測驗
判斷以下函數是否有凹四邊形單調性
F(x,y)=xy

F(x,y)=(x−y)2

F(x,y)=sx+ty
s,t 是遞增數列
F(x,y)=aA(x,y)+bB(x,y)
a,b≥0
A, B 有凹四邊形單調性
四邊形不等式(交叉與包含)
如果對於任何i<i′≤j<j′
都有F(j,i)+F(j′,i′)≤F(j,i′)+F(j′,i)
則 F 滿足凸四邊形單調性。

舉一隅以一隅反
如果對於任何i<i′≤j<j′
都有F(j,i)+F(j′,i′)≥F(j,i′)+F(j′,i)
則 F 滿足凹四邊形單調性。

還有
判斷以下函數是否有凹四邊形單調性
C 是正整數數列,K 是正整數

我也不知道答案
[HNOI 2008] 玩具裝箱
它也可以斜率優化

[POI 2011]Lightning Conductor

F(i,j)=
反芻
凹
凸
四邊形不等式
凹跟凸有什麼用
四邊形單調性
2D/1D四邊形優化
長相(通常):
dp[i][j]=i≤k≤jmin{dp[i][k]+dp[k][j]+w(i,j)}
從夾在裡面的東西轉移
尋找蘿莉第二彈
額,先別管題敘
算了還是看一下好了
這是建中校內賽題
尋找蘿莉第二彈
dp[l][r]=l≤k≤rmin{dp[l][k]+dp[k][r]+sum(l,r)}

尋找蘿莉第二彈
dp[l][r]=l≤k≤rmin{dp[l][k]+dp[k][r]+sum(l,r)}
凸??
好啦通常w凸dp就凸 QQ 然後這就凸凸的
重要定理
設pi,j 是dp[i][j] 在轉移時所找到的最佳轉移點,且dp 滿足凸四邊形不等式,則:
pi,j−1≤pi,j≤pi+1,j
打無限個星號 考翻了


2D/1D凸四邊形優化
dp[i][j]=i≤k≤jmin{dp[i][k]+dp[k][j]+w(i,j)}
dp[i][j]=pi,j−1≤k≤pi+1,jmin{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)的做法
1.石子合併
2.OBST
2D/1D凸四邊形優化
使用時機
1. DP式是2D/1D的
2. 滿足四邊形不等式
3. 至少w要凸
2D/1D凹沒有好性質
所以只能枚舉i,讓dp狀態變成一維
用N次的1D/1D 解決
時間複雜度N2logN。
1D/1D四邊形優化
a.k.a. 決策單調性優化
長相(通常):
dp[i]=0≤j<imin{dp[j]+w(i,j)}
dp[i]=0≤j<imin{w(i,j)}
枚舉前面的點轉移
Lightning Conductor

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

先假設i>j 把絕對值拆掉
Lightning Conductor
凸?
Lightning Conductor
證明四邊形不等式
w(a,d)+w(b,c)≤w(a,c)+w(b,d)
兩邊消掉一些東西
d−a+c−b≥c−a+d−b
兩邊平方,排序不等式
bd+ac≥bc+da
Lightning Conductor
有單調性了 XD
多米諾效應:
我現在比你差,未來一定比你差

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]:考慮前i天,第i天不吃拉麵的最高分
dp[i][1]:考慮前i天,第i天吃拉麵的最高分
轉移
dp[i][0]=max(dp[i−1][0],dp[i−1][1])
dp[i][1]=i−k≤j<imax(dp[j][0]+S[i]−S[j])
1D/1D四邊形優化經典題
ans[i]=j<imax{A(j,i)}
A(j,i)是以第j條線為下界,第i條橫線為下界的最大矩形面積
可以證明轉移點遞增
再用1D/1D凸或分治解決
倒過來考慮
狀態
dp[i]代表放完前i個東西後的最大值
轉移
dp[i]=i−k≤j<imax(dp[j]+Sj−(i−j)2)
小心處理過期
狀態
dp[i]表示買進第i台機器時,擁有的最多錢數
轉移
dp[i]=j<i,dp[j]≥0max(dp[j]+(Di−Dj)2∗Gj+Rj−Pi)
狀態
dp[i][j]表示考慮前i個房子,蓋了j座郵局的最短距離和
w[i][j]表示在第i個房子和第j個房子中,只蓋一座郵局的最短距離和
轉移
dp[i][j]=k<imin(dp[k][j−1]+w[k+1][i])
狀態
dp[i][j]表示考慮前i個洞,放入前j隻老鼠
w[i][j]代表前j隻老鼠都跑到第i個洞所需的花費
轉移
dp[i][j]=k+c[i]>jmin(dp[i−1][k]+w[i][j]−w[i][k+1])
狀態
dp[i][j]表示考慮前i個洞,放入前j隻老鼠
w[i][j]代表前j隻老鼠都跑到第i個洞所需的花費
轉移
dp[j]=k+c>jmin(dp1[k]+w[j]−w[k+1])
狀態:
dp[i][j][k]代表考慮前i隻pokemon,用了j個紅球、k個黑球的隻數最大期望值
轉移:
dp[i][j][k]=max(dp[i−1][j][k],dp[i−1][j−1][k]+pi,dp[i−1][j][k−1]+ui,dp[i−1][j−1][k−1]+ui+pi−pi×ui)
狀態:
dp[i][j][0]代表前i組,取了j組,第i組不取
dp[i][j][1]代表前i組,取了j組,第i組要取
轉移:
dp[i][j][0]=min(dp[i−1][j][1],dp[i−1][j][0])
dp[i][j][1]=dp[i−1][j−1][0]+1
狀態
dp[i][j]表示考慮前i個房子,蓋了j座郵局的最短距離和
w[i][j]表示在第i個房子和第j個房子中,只蓋一座郵局的最短距離和
轉移
dp[i][j]=k<jmin(dp[k][j−1]+w[k+1][j])
狀態
dp[i][j]表示考慮前i個房子,蓋了j座郵局的最短距離和
w[i][j]表示在第i個房子和第j個房子中,只蓋一座郵局的最短距離和
轉移
dp[i]=k<imin(dp[k]+w[k+1][i]+cost)
DP優化
By Zi-Hong Xiao
DP優化
- 1,274