注:這是dp套路整理裏面題的題解qwq
一、簡單dp
1.1 快速冪優化dp
1.1.1 模板題 斐波那契數列
大家都知道,斐波那契數列是滿足如下性質的一個數列:
Fn={1 (n≤2)Fn−1+Fn−2 (n>2)
請你求出Fn mod 109+7(1≤n<263)的值。
構造出矩陣快速冪轉移矩陣:
[FnFn−1]=[1110]∗[Fn−1Fn−2]
於是有[FnFn−1]=[1110]n−2∗[F2F1]=[1110]n−2∗[11]
於是可以用矩陣快速冪求解Fn的值。
代碼略
1.1.2 模板題 zyd的妹子其二
zyd要妥善安排他的後宮,他想在機房擺一羣妹子,一共有n個位置排成一排,每個位置可以擺妹子也可以不擺妹子。有些類型妹子如果擺在相鄰的位置(隔着一個空的位置不算相鄰),就不好看了。假定每種妹子數量無限,求擺妹子的方案數。
輸入有m+1行,第一行有兩個用空格隔開的正整數n、m,m表示妹子的種類數。接下來的m行,每行有m個0/1字符,第i行第j列爲aij。若aij爲1,則表示第i種妹子第j種妹子不能排在相鄰的位置,輸入保證對稱。n≤109,m≤100
令dp[i][j]表示放了i個妹子,最後一個妹子是j的方案數。
dp[i][j]=∑ajk==0dp[i−1][k]
令bij=1−aij
於是得到⎣⎢⎢⎢⎢⎡dp[i][m]dp[i][m−1]dp[i][m−2]...dp[i][1]⎦⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎡b11b21b31...bm1b12b22b32...bm2b13b23b33...bm3...............b1mb2mb3m...bmm⎦⎥⎥⎥⎥⎤∗⎣⎢⎢⎢⎢⎡dp[i−1][m]dp[i−1][m−1]dp[i−1][m−2]...dp[i−1][1]⎦⎥⎥⎥⎥⎤
代碼和剩下的步驟略。
1.2 LIS & LCS的優化
1.2.1 模板題 LIS
給定一長度爲n的數列,請在不改變原數列順序的前提下,從中隨機的取出一定數量的整數,並使這些整數構成單調上升序列。 輸出這類單調上升序列的最大長度。n≤105。
fi=maxj=1i−1{fj+1},aj<ai。離散化後用樹狀數組記錄下≤x的f的最大值,遍歷求解。
二、揹包
2.1 01揹包(略)
2.2 完全揹包(略)
2.3 多重揹包
2.3.1 模板題 寶物篩選
小 FF 找到了王室的寶物室,裏面堆滿了無數價值連城的寶物。
小 FF 對洞穴裏的寶物進行了整理,他發現每樣寶物都有一件或者多件。他粗略估算了下每樣寶物的價值,之後開始了寶物篩選工作:小 FF 有一個最大載重爲 W 的採集車,洞穴裏總共有 n 種寶物,每種寶物的價值爲 vi,重量爲 wi,每種寶物有 mi 件。小 FF 希望在採集車不超載的前提下,選擇一些寶物裝進採集車,使得它們的價值和最大。n≤100,∑mi≤105,0≤W≤4∗104。
令dp[i][j]表示前i種寶物,目前載重爲j的最大價值。
轉移方程:dp[i][j]=max{dp[i−1][j−k∗wi]+k∗vi}。
注意到對於每個i,j和j−k∗wi是模wi同餘的。也就是說j只會被與j模wi相同的數影響。
設j=p∗wi+r,則轉移方程可化爲dp[i][j]=max{dp[i−1][k∗wi+r]+(p−k)∗vi}(p−mi≤k≤p)
拆開p∗vi這項常數,得到dp[i][j]=max{dp[i−1][k∗wi+r]−k∗vi}+p∗vi(p−mi≤k≤p)
發現這就是一個滑塊窗口,所以用單調隊列亂搞。
#include<stdio.h>
#include<cstring>
#include<algorithm>
#define re register int
using namespace std;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=10*x+ch-'0';
ch=getchar();
}
return x*f;
}
const int Size=100005;
int n,V,v[Size],w[Size],num[Size],dp[Size];
int hd,tl;
struct node {
int id,val;
} Queue[Size];
inline void push(int id,int val) {
while(hd<=tl && val>Queue[tl].val) tl--;
Queue[++tl].id=id;
Queue[tl].val=val;
}
inline void pop(int id,int num) {
while(hd<=tl && Queue[hd].id+num<id) hd++;
}
int main() {
n=read();
V=read();
int ans=0;
for(re i=1; i<=n; i++) {
v[i]=read();
w[i]=read();
num[i]=read();
if(!w[i]) {
n--;
ans+=v[i]*num[i];
}
}
for(re i=1; i<=n; i++) {
for(re r=0; r<w[i]; r++) {
int lim=(V-r)/w[i];
hd=1,tl=0;
for(re p=0; p<=lim; p++) {
push(p,dp[p*w[i]+r]-p*v[i]);
pop(p,num[i]);
dp[p*w[i]+r]=max(dp[p*w[i]+r],Queue[hd].val+p*v[i]);
}
}
}
printf("%d",dp[V]);
return 0;
}
2.3.2 例題 shopping
2.4 分組揹包
2.4.1 例題 [HNOI2007]夢幻島寶珠
三、區間dp
3.1 樸素區間dp(略)
3.2 斷環爲鏈(略)
3.3 四邊形不等式優化
3.3.1 例題 [NOI1995]石子合併
四、狀壓dp
4.1 樸素狀壓dp
4.1.1 模板題 關燈問題II
4.1.2 模板題 [SCOI2007]排列
4.2 插頭dp
五、多維dp
5.1 樸素多維dp
5.1.1 模板題 烏龜棋
5.2 多維dp優化
六、樹形dp
七、期望dp
7.1 樸素期望dp
7.1.1 模板題 換教室
7.1.2 例題 World of warcraft
7.2 高斯消元優化循環轉移
7.2.1 例題 [HNOI2013]遊走
八、數位dp
8.1 樸素數位dp
8.1.1 模板題 [SCOI2009]windy數
8.1.2 模板題 [ZJOI2010]數字計數
九、決策單調性優化
9.1 與決策單調性相關的定義及性質(略)
9.2 單調隊列/二分查找優化
9.2.1 例題 [NOI2009]詩人小G
9.2.2 例題 數據分塊雞
9.3 斜率優化
9.3.1 [ZJOI2007]倉庫建設
9.4 cdq分治套斜率優化
9.4.1 模板題 [SDOI2012]任務安排
9.4.2 模板題 [CEOI2017]Building Bridges
十、數據結構優化
10.1 簡單數據結構優化dp(略)
10.2 線段樹/樹狀數組優化dp
10.2.1 模板題 摔跤選手yxc
10.2.2 例題 [SCOI2014]方伯伯的玉米田
十一、動態dp