动态 dp

动态 dp

没写代码,暂且不知道有多少处笔误,还需要好好理解。。


动态 dp

矩阵乘法大家都会!dp 大家都会!线段树大家都会!

一些线性 dp 可以写成矩阵乘法的形式,这里矩阵乘法可能是 (+,×),也可能是 (max,+),也可能是 (min,+) 等等,但是只要有结合律就可以。

在每个点处的转移都写成一个矩阵的形式,而要询问单独拿出来一段区间 dp 的结果,就是询问这个区间的矩阵乘积。

基于这个原理,可以用数据结构来维护区间矩阵乘法的结果。这个就是动态 dp。

一句话:将 dp 转移写成矩阵乘法,然后用数据结构维护矩阵乘积。

例题

给定 01 串,支持单点修改,区间询问单独把这个 01 串拿出来后,每次可以 +2i 或者 2i,最少几次把其消为 0

线段树维护一个分治信息,大概维护一个前面有没有给自己一个进位 0/1,会不会给后面一个进位 0/1,最小代价是多少。

可以用矩阵解释,这个就是动态 dp?

P4719 "动态 DP"&动态树分治

序列上的带修最大权独立集我们都会动态 dp,现在最大权独立集上树了。

考虑从序列到树的常见套路是静态LCT重链剖分,对于一条重链直接维护一个动态 dp 的矩阵,但是轻儿子的贡献怎么算?

gx,0/1x 节点不选/选的,并且不考虑重儿子时的 dp 值是多少。

对于一条重链,如果每个节点的 g 都维护出来了,那么这条重链上的动态 dp 就能维护出正确的答案。

考虑到最大权独立集具体的式子,一个儿子 dp 值改变之后,对父亲的 g 值的修改可以直接 O(1) 加减出来,那么树剖修改的时候跳重链的时候,在父亲的重链的线段树上单点修改把父亲的 g 值改掉就可以了。

时间复杂度大概是 O(nlog2n),再带一个矩阵乘法的复杂度。

游戏

树上每个节点有若干个石子,两个人轮流在树上取石子,先手可以任选一个位置开始取一个石子,接下来每个人取石子的节点必须和对方上次取石子的节点相邻。单点修改,每次修改求谁必胜。

首先先先考虑没有修改的情况:

考虑给每个树上每个石子一个节点,如果两个石子在树上相邻就连一条边。树是二分图,所以这样建图出来也是一个二分图,那么这就是一个二分图博弈,后手必胜当且仅当这个二分图有完美匹配。(为什么?)

考虑这个匹配可以直接贪心匹配,每次尽可能的让叶子往上配对,然后将叶子删掉。

于是这个等价于对于每个点记录一个 fi 表示以 i 为根的子树,奇数层 偶数层的石子数,那么就有一个 fu=auvson(u)fv

那么存在一个匹配就当且仅当所以 f 非负并且 f(1)=0

树剖维护 f,奇偶层分开用线段树维护即可。

保卫王国

大家都知道 最小权点覆盖集 = 所有点的权值之和 最大权独立集。

也就是两者互为补集。

强制一个点必须选,就把它权值设为 0,最后给最小权点覆盖集加上原先的权值即可;如果一个点必须不选,就把它权值设为

这样就变成了动态 dp 模板了,总权值减去最大权独立集,当然直接推最小权点覆盖的动态 dp 也可以。

ZJOI2019 Minimax 搜索

对于一个答案 k,最优的策略就是与 W LCA 深度为奇数的的 +k,偶数的 Wk.这样就知道每个叶子应该是 +k 还是 k 了。

考虑计算答案 k 的方案数,差分一下即为所求。

那么考虑 fi,0/1/2 表示 i 子树内,i 节点权值变 >W /变 <W /变 =W 的集合数。注意到这个 f 总和是 2cc 是叶子个数,所以可以只记录其中两个即可。但是每次都用给 2c 转移起来太麻烦了,直接考虑将方案数改成概率。

那么记 fii 子树内使得 i 权值变 <W 的概率,gi 表示 i 子树内使得 i 权值变 >W 的概率。

那么每次 kk+1 的时候均摊至多会有两个叶子的 fg 会发生改变。

动态 dp 维护即可,有亿、小细节。

posted @   do_while_true  阅读(272)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?

This blog has running: 1845 days 1 hours 34 minutes 12 seconds

点击右上角即可分享
微信分享提示