动态dp
动态DP
基础概念#
从一道简单的问题说起#
- 有一个长度为 的序列 ,每个数可以选或者不选,但相邻两个数不能同时选,最大化选出的数的和。
有一个简单的 ,设 表示前 个数,第 个数是否选了的最大价值,转移时
现在把这个问题加强一下:
- 有一个长度为 的序列 ,每个数可以选或者不选,但相邻两个数不能同时选,最大化选出的数的和,需要支持单点修改和对区间查询。
我们可以把转移写成矩阵的形式:
其中矩阵乘法定义为 乘法。
不妨令
那么答案可以写成
现在是单点修改,区间查询,我们可以用线段树维护区间内的 的乘积,因为矩阵乘法有结合律所以这样做是正确的。
这样子就可以在 复杂度内解决这个问题。
类似上面的过程,在解决动态,范围查询的动态规划问题时,用数据结构维护矩阵乘法的方式也被称为动态 dp,也可以简称为 ddp。
练习 [ABC246Ex] 01? Queries#
练习 CF750E New Year and Old Subsequence#
树上的情况(静态)#
P5024 [NOIP2018 提高组] 保卫王国#
设 表示 子树内 , 是否选了的最小代价,转移是显然的。
同时换根 dp 求出 代表 子树外, 是否选了的最小代价。
询问时,把所有点拆成 子树内, 子树内, 的子树外, 的路径上。
前三者分别是 ,对于后者,我们考虑倍增,设 表示 到 的 级祖先这段范围内(不算 子树,但是算路径上其他点的子树), 是否选了, 的 级祖先是否选了的最小代价。
那么询问时倍增出一段链上的 即可,复杂度 。
练习 P8820 [CSP-S 2022] 数据传输#
树上的情况(动态)#
P4719 【模板】"动态 DP"&动态树分治#
没有修改时,设 表示 子树内,节点 是否选了的最大权值和,转移是显然的:
- 。
- 。
但是树的结构不太好维护信息,因此考虑做一下轻重链剖分,设 为 的重儿子。
现在考虑把每个点的 dp 写成关于其重儿子信息的矩阵,轻儿子的信息暴力维护。
对于轻儿子,维护
。
。
那么每条重链上的转移可以写成:
此时就可以维护每条重链的乘积了。
单点修改时,注意到只有 到根这条路径上的点的信息需要修改,并且 会发生变化的点一定只有每条重链的链顶的父亲,一共不超过 个点,每次修改过 之后重新更新一下所在重链的线段树的区间矩阵,再修改该重链链顶父亲的 ,以此类推,需要修改 次线段树,因此复杂度为 。
练习 P6021 洪水#
全局平衡二叉树#
全局平衡二叉树是一个可以将普通树剖套线段树变成 1log 的东西。
还是轻重链剖分,对于每条重链,建立一棵特殊的线段树。
设 为 的轻子树大小,每次选取 的带权中点作为分界线递归。
考虑复杂度,定义一个线段树节点的重量为区间内所有点的轻子树大小和,定义一个线段树叶子的重量为轻子树的大小和,容易发现每次跳父亲重量倍增,因此只会跳 次。
P4751 【模板】"动态DP"&动态树分治(加强版)#
进阶题目#
CF1286D LCC#
考虑最先碰撞的一定是相邻两个粒子,具体的,可以相遇,向左追击,向右追击三种。
把所有碰撞所需时间排序,枚举最先碰撞的是哪种情况,那么就是要求时间更小的碰撞都不发生的概率。
相当于有若干限制,形如 不能同时选 和 ,记为 。
那么考虑依旧维护矩阵乘积,转移可以写成
单点更新,全局查询,写一个线段树即可。
复杂度 。
P4426 [HNOI/AHOI2018] 毒瘤#
题目保证了 ,也就是说,如果我们找出一颗生成树,那么只会有不超过 条非树边。
考虑容斥, 枚举每条非树边是否被钦定,对于每条非树边,钦定它连着的两个点同时被选,那么现在问题就是,对于一棵树,每次钦定两个点必须选,或者取消钦定,求这棵树的独立集个数。
用树剖/全局平衡二叉树维护动态 dp 即可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】