动态规划
动态规划
1.普通(线性)动规
判断一道题是动归最简单的办法就是看数据范围,一般数据范围比较小的可以是动归。
动归要先设计出状态,再想办法搞状态转移方程。最后考虑初始值,边界,答案是什么(不一定就是\(dp[n]\)),还有空间和时间。
例题:
P4158 [SCOI2009]粉刷匠(这题前面求每行画几笔得到的最多答案是线性\(DP\),后面是分组背包)
2.背包
TIP:背包其实并不是怎样都能压维,有时候物品体积为0时就不能压维。
1. 01背包与多重背包
01背包:\(f[i][j]=max(f[i-1][j-v[i]]+w[i])\)
多重背包:每个物品可以拿多次。有时候可以进行二进制优化。
例题:
P1833 樱花
2. 完全背包
每个物品可以拿无限次。
\(f[i][j]=max(f[i][j-v[i]]+w[i])\)
压维写法比较常见:
\(f[j]=max(f[j-v[i]]+w[i])\)。(\(j\)正序枚举)
3. 分组背包
\(f[k][j]=max(f[k-1][j-v[i]]+w[i])\)。
例题:
P1174 打砖块
3.树形DP
1. 普通树形DP
树形DP,顾名思义,就是在树上DP,那么它的状态一般与其父亲,儿子有关。
2. 换根DP
这个博客呢,不是说不写,我写的时候肯定就写了对吧?
例题:
3. 基环树
把图看成一个环,环上的每个点外接一棵树,那么树上DP,环上特写即可。
例题:
P4381 [IOI2008] Island
P2607 [ZJOI2008] 骑士
4. 树形背包
树形DP,但是涉及背包。
4.构造类动归
这种题一般询问构造一种序列之类的方案数,
5.状态压缩DP
一些比较难表示的状态,但是状态数又比较少,可以使用状压DP。
6.区间DP
其通式为:\(f[i][j]\)表示从\(i\)到\(j\)的区间怎么样。更新的时候一般要枚举断点。
例题:
P3147 [USACO16OPEN]262144 P
P4290 [HAOI2008] 玩具取名
P4302 [SCOI2003]字符串折叠
P2470 [SCOI2007]压缩
7.概率DP
计算一些人获胜概率,像是博弈论之类。
8.数位DP
这个博客呢,不是说不写,我写的时候肯定就写了对吧?
优化动归的方法
时间
1. 前缀和
形如\(f[i][j]=\sum_{k=1}^{j-1}f[i-1][k]+max(f[i-1]l])\)。
这样的式子可以用前缀和优化大幅度优化复杂度(写起来也很轻松)。
2. 树状数组(线段树)
有时候,前缀和受限制了,就可以使用树状数组或线段树来处理一段区间的值。
3. 单调队列
也是对区间值的维护,限制比线段树大,但是速度快代码简单。
例题:
琪露诺
4. bistset优化
一般是优化背包,如果背包的值只有0和1,那么它就登场了。
5. 李超树(斜率优化)
斜率优化详情
李超树,可以插入一个一次函数,然后查询,还不用保证单调性,很方便对吧。
6. 四边形不等式
例题:
P1880 [NOI1995] 石子合并(我知道你很想打暴力,但你先别打)
7.cdq分治
8.矩阵快速幂优化DP
空间
1. 滚动数组
有些题目更新下一层时只需要用到上一层(如01背包),那么这一维前面的数组用完就可以扔了,只需两个数组上下互相更新即可。
2. 压维
有些无用的维度(状态一样的维度,可以用前几维推出的维度)可以省略。
例题:
业务员(第一个业务员可以压维)
P2224 [HNOI2001]产品加工
经典模型
1.LIS与LCS
LIS现在我一般偏向写树状数组的写法。按时间顺序依次插入每个点,用树状数组查找比目前点小的点的最大\(DP\)值,复杂度\(O(n\log n)\)。
求一个排列的LCS,那么只要把第一个排列按顺序映射为\(1,2,3...\),然后再将第二个排列用第一个排列的映射值。那么此时第二个排列的LIS即为LCS。证明:如果两个点可以以LIS连接在一起,那么递增实质就是他们在第一排列中顺序从小到大。
2.悬线法
3.线段选取
把一般DP问题化作一堆线段选取问题。
例题:

浙公网安备 33010602011771号