基于结构的 DP 入门
仅记录我知道的方法,个人的见识很少,理解很浅。分类和一部分内容参考《dp 题方法总汇》。
生成结构
DP 主要用于生成结构和模拟过程,生成结构的方式同样是一种过程。
集合(背包)
无序。
- 以任意顺序转移,依次确定每个数的系数。
具体的技巧:
- 合并物品:
- 限制总和转多重背包。
- 多重背包的二进制拆分和单调队列优化。
- 重量限制大:
- (最优化)价值小:换维。
- 重量小:
- 完全背包:同余最短路。
- 对二进制进位 DP(类似数位 DP)。
- (计数)转 GF,提取系数,直接做或用 Bostan-Mori。
- 与过程形成双射,对过程 DP:添加或整体 \(+1\)。
排列
有序,且性质优秀。
两种题:统计排列,统计映射(位置分配)。
排列即位置与值的二分图完美匹配:
- 将匹配拆为先后两部分,按权值依次一起处理左右部点,记录已匹配的对数:P14364 [CSP-S 2025] 员工招聘、CF285E Positions in Permutations。
- 按左部点/右部点(排列/逆排列)顺序依次添加匹配:
- 考虑已匹配的另一部点的相对顺序:
- 依左部点(位置):AT_dp_t Permutation)。
- 依右部点(数值):排列逆序对 DP、连续段 DP。
- 考虑另一部点的绝对大小(通常依赖单调性):
- 依左部点:只填一个单调子序列,剩下的组合计数解决;又如 CF1437F Emotional Fishermen。
- 依右部点:构建笛卡尔树的区间 DP(分成子问题后右部点看相对顺序,归并修正贡献);又如:AT_arc093_d [ARC093F] Dark Horse。
- 考虑已匹配的另一部点的相对顺序:
序列
有序,比排列更复杂。
二分图视角:一个左部点恰匹配一个右部点,一个右部点可匹配多个左部点。
防止算重:
- 重排类问题,先对映射计数,再除以阶乘:AT_abc431_f [ABC431F] Almost Sorted 2。
- 对相同数值一起转移。
其他和排列类似。
一些特殊序列的常用方法:
字符串
可以视作自动机上的路径。
- 从前往后或从后往前一位位填,构建一个自动机状态记录关键信息:AT_agc046_d [AGC046D] Secret Passage。
数
统计范围:\([1,x]\) 中的所有数,\(x\) 在 \(y\) 进制下有 \(n\) 位。
本质是带“数的范围”限制的字符串,所以给自动机加状态即可。
- 从高位到低位填:记录是否顶上限、是否已有非 \(0\) 位,通常采用记搜,状态表示确定高位限制后的贡献和。
- 从一段区间的两端扩展:状态里钦定和哪段区间匹配,并记录当前的数与 \(x\) 的这段区间的大小关系,最后取以 \(x\) 的最低位为一端的区间(假定 \(x\) 无前导 \(0\),注意若包含最高位,则只能 \(</=\),否则可以 \(</=/>\))。例题:P9129 [USACO23FEB] Piling Papers G。
括号序列
栈、树等结构都可以视作括号序列。
- 从左到右填,记录未匹配的左括号数:CF1153F Serval and Bonus Problem。
- 状态表示 \((\ldots)\),初始为空,有拼接和围括号两种转移:2025.9.25 T4。
- 折线图。
序列上的结构:
分段
- 记录段的结尾/钦定当前是段的结尾:2025.10.25 T2。
区间
在序列或数轴上,有关于区间的限制/贡献,需要选择一些位置或一些区间。
- 离散化后拆成若干极小段,记录被选择/被覆盖的最右极小段(或钦定当前这段就是):P9871 [NOIP2023] 天天爱打卡。
- 将区间按左端点/右端点排序,依次考虑每个区间,把 DP 值挂到左端点/右端点上:2025.11.8 T2。
树/森林
我咋没怎么做过用 DP 生成树的题啊。
- 有根树有天然的子结构划分,而无根树可以转成有根树。
- (有标号)无限制、限制或贡献与度数有关时,可以用 Prufer 序列统计无根树,有根树可以视作选一个根。
有根树的生成方式:
- 初始为空,添加根后拆成若干棵子树(括号序列的这种转移相当于生成森林):CF438E The Child and Binary Tree、51nod-1728 不动点(都是多项式题)。
- 与深度强相关时,按深度一层层填:P3959 [NOIP 2017 提高组] 宝藏。
对于树,更多考察的是给定树结构上的 DP,而非生成一棵树的 DP。
树/森林上的结构:
简单路径/虚树
- 树上合并,设 空、续(有向上的插头)、止 三种状态:P8867 [NOIP2022] 建造军营。
(可以看出提前钦定的插头可以使 DP 更清晰。)
树上背包
- 树上合并:每个结点上只有一个重量为 \(1\) 的物品时,时间复杂度为 \(O(nm)\)。P4516 [JSOI2018] 潜入行动。
- DFS 序上增量转移:针对只求根信息的树上依赖背包,时间复杂度为 \(O(nm)\),且便于多重背包的单调队列优化。P6326 Shopping。
外向/内向树拓扑序计数
可以 DP 得到结论,也可以用组合做法求出:
\[n!\over\prod_{u=1}^nsiz_u
\]
记得曾经有一道对前缀 \(\max\) 建树的题,但我忘了叫啥了。
森林连通块数量
- 点数 \(-\) 边数;进一步有欧拉公式。
DAG
- 删去或添加所有入度/出度为 \(0\) 的点,归到子问题。可以视作给 DAG 分层,且层数即最长路(存疑)。
- 按到某点/从某点出发的最长路分层,一层层扩展:P11173 「CMOI R1」We Want To Run / Nilpotent。
图
- 通常对点集状压,考虑导出子图中的边或所有边。
图上的结构:
路径
- 关键信息:起点、终点。
生成树/斯坦纳树
- 仿照树的生成方式,先从根连向新的根,再合并根相同的若干子树。实际转移时以点集为阶段,所以先合并再延伸。
独立集等(相邻)
增量构建,考虑一段前缀的点,记录与后缀可能相邻的点,跑轮廓线 DP。
找尽量短的轮廓线:
- 树:重链剖分或点分树。
- 网格图:选行、列中短的那个。
连通性相关
- 不连通 \(\to\) 连通:代表元容斥或求 \(\ln\)。
- 连通 \(\to\) 不连通:直接拼接或求 \(\exp\)。
2025.11.26
浙公网安备 33010602011771号