动态规划总结
动态规划在考试中一直都是一个大头项,此处仿照 OI-Wiki 的方式对 DP 进行总结。
背包 DP
背包分为:01 背包(每个只能选一次),完全背包(每个选择无限次),多重背包(每个可以选若干次),依赖背包(有前置需求),分组背包(同一组只能选若干个)。
01 背包
通常为双层 DP,第一层枚举物品,第二层枚举容量,第二层需要逆向。
- 双栈使01背包可逆。
在使用双指针优化 dp 时,有时并不容易进行删除操作,此时我们就可以使用两个栈来维护我们的双指针。例题:版子。
完全背包
通常为双层 DP,第一层枚举物品,第二层枚举容量,第二层需要正向。
多重背包
一方面,可以通过二进制将若干相同物品压成一个物品,化为 01 背包,另一方面,使用单调队列。
依赖背包
类似于一个树形结构,在每个儿子间 01 背包即可。
分组背包
将一组的背包一波一起转移即可。
区间 DP
区间 DP 的状态与一般的 DP 不大相同,
常见技巧:拆环成链,左右端点标记,四边形不等式一维优化,四边形不等式二维优化。
标志的数据范围应当在
树形 DP
树形 DP 典型的应该是这题。
在处理时,发现有若干对矛盾或是依赖的情况并且形成一个有向无环图,抑或是树形时,就可以使用。
分类:
- 链上的 dp,
其实感觉和线性 dp 区别不大,在链上的 dp,常常利用树链剖分。 - 子树内的 dp,在几个子树间选择、决策。
小技巧:
- 上下界优化(常见技巧)。
- 继承优化(让重儿子继承父亲的指针,这样不需要在重儿子转移(
有点像树上启发式合并?)),Hotel加强版。 - 换根这个技巧,
应该不用说才对,用来维护转移根节点时,只有几个节点的 dp 数组发生变化,[POI2008] STA-Station。 - 树链剖分,只能说非常好用。对于路径上的 dp,但凡线性上可以使用线段树维护,基本上都可以用树链剖分。[TJOI2015] 旅游 。
- 倍增,适用性强,但是常数略大。
- 树上启发式合并(Dsu on Tree)。
- 长链剖分优化。
- 不知道这几年发了什么疯,常常与二分结合[NOIP2012 提高组] 疫情控制。
- 现在的树形 dp 也往往没有树形,比如依托于 AC 自动机的树上差分,看似是数论的树形 dp 都可能捡到。
- 在一些题中有换根操作时,往往并不需要换根,可以考虑根相邻交换的影响,就能够转移换根的答案影响,一方面,子树修改可以利用判断当前根是否在修改子树中进行区间修改。
状压 DP
状压 dp 是运用二进制枚举来进行转移的 dp,其数据范围极具特色,多为
一部分技巧:
- 子集枚举优化至
:for(int P=st;P;P=(P-1)&st)
。 - 贪心进行转移。
- 找基准点进行转移。
- 状态压缩:
- 将二维压成一维。P4297 [NOI2006] 网络收费。
- 将确定的一个二进制位压走。
- 以某个结点为一维进行辅助转移。最小斯坦纳树。
- 双向状压,类似于 meet in the middle。P4799 [CEOI2015 Day2] 世界冰球锦标赛。
- 状压时要仔细抉择以什么为状态,换个状态可能在空间上就可以进一步优化。
数位 DP
数位 dp 的核心事实上就是差分,在想到差分后的 dp 往往比较显然。
数位 dp 往往都是这样的题型,给定一个闭区间
数位 dp 实质上就是正常的 dp,是按照每一个数位进行决策,然后再进行记忆化而已。
其数据范围与状压 dp 同具特色,多为
多以记搜写法,简单方便,但是在需要优化空间时,就要转化成递推,滚动数组即可。
概率 DP
概率 dp 同下方的计数概率 dp 是最令人讨厌的两大 dp,题目特色体现在题面。
简单技巧:
期望 DP
烦人题,简单总结一下方法。
- 容斥。
- 高斯消元。
- 有时在贡献较小时,可以转化成概率 dp,即期望等于
贡献 概率。P9346 无可奈何花落去。
计数 DP
计数 dp 是 dp 中最为烦人的之一,没有一个大的方向感,只能靠刷题锻炼题感,题目特色体现在题面。
- 不重不漏
- 围绕基准点来防止重复,CF559C。
- 等效代换,离散化思想:
- 用
的数,最左边的为 。 - 用
个不同的数,最左边的排名为 。
- 用
- 将等于转化成小于等于,再用容斥求解。
- 利用根号分治。
- 计数转概率,乘上总方案数。HDU5378。
- 与组合数学常常结合。
- 多利用打表找规律,不必全部观察,利用代码确认规律,大胆猜测,小心检查,直接莽结论,证明什么的有时间在弄。
。
DP 优化
空间上优化
空间上,有时可以将可行型的二维数组,转化成一维的最优解,或是用 bitset 优化。
时间上
在写 dp 时,常常会出现一些极具性质的转移,此时我们可以优先考虑优化转移,实在不可,再优化状态。
数据结构优化
线段树优化
用线段树的区间修改,区间查询维护转移,可以在转移时发现多为区间上的修改,即可使用。
线段树优化 dp 现在往往与单调栈相结合,这种在转移时可以发现转移除去
使用树状数组,适用范围与线段树相似,但是常数更小,也有一点约束性。
使用单调栈,多为在没有查询范围,但是在某个权值上的最优转移,大多与其他优化方式相配合,如斜率优化。
使用单调队列,多为转移有区间限制,并在某个权值上的最优转移,如经典滑动窗口。
分治优化
-
根号分治
对于一些问题,我们在某一个值小时另一个就大,这个值大后另一个值就会变小,我们就可以利用这个小的值来优化。
例如:哈希冲突。 -
CDQ分治
主要用来维护三维偏序,是比较经典的解法。
第一维,通过主函数排序。
第二维,通过归并中合并解决。
第三维,通过数据结构解决。
三维偏序(陌上花开)。
OI Wiki。 -
分治
- 可以对中间结点分开分治。
- 对于最大值进行分治。
- 分治本意就是分而治之,将问题分成两个问题,然后两个区间可以进行一定程度的拼接,因此有时会用线段树优化。
斜率优化
在转移时我们有时会得到
[SDOI2012] 任务安排。
OI-Wiki。
四边形不等式(决策单调性)
决策单调性指的是形如
设
可以用来辅助转移一维 dp,二维 dp。
OI-Wiki。
矩阵优化 dp
在转移时,发现转移的方式都是一模一样的,并且转移次数极多,可以考虑用矩阵优化我们的 dp。
使用矩阵快速幂来优化转移次数,可以将一个次数极多的转移优化至
矩阵优化 dp 有时不仅代表优化转移,更是利用矩阵的方式来使代码减重,也有运用 线段树+矩阵 来实现可中间修改的 dp。当然,动态 dp 也在其内。
特殊小技巧
- 在转移时间复杂度较小时,并且有修改操作时,可以使用线段树来辅助转移计算。[COCI2015-2016#1] RELATIVNOST
- 有时,我们可能不仅仅可以记忆化我们的 dp 数组,我们在辅助转移中,可能也有一部分是反复计算的,同样可以记忆化。为了方便,有时可以使用间接递归来解决。P9229 扩展九连环。
- 高斯消元可以使用稀疏矩阵优化,可能可以拿到更多的分。
- 在状态可能比较少时,我们可以使用 unorded_map 来优化我们的空间,可能可以导致水到更多的分,以至于满分。
- dp 万变不离其宗,终究是转移之后取优,取和,因此记忆化 dfs 也是一种相当可取的写法,尽管可能因此栈溢出。
- 有时候区间查询可以化成
的前缀与 的后缀来处理。 - 区间查询时可以考虑使用倍增(二进制拆解)。
- dp 的重中之重就在于暴力,暴力写的好,正解思路没烦恼,可以尝试把暴力的形式推广,用不同的方式,可能就能找到优化的方法。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现