MnZn 的DP杂篇

前言

一切仅为个人理解,一点都不严谨,若有误请大佬指出 orz


乱七八糟的

转移多的区间DP之去重

首先,这是很显然的区间 DP 。但是只建两维状态就需要去重,作为一个蒟蒻我最不喜欢的就是去重了,所以可以再给状态多设一维方便转移

根据题意,新开的一维代表了当前括号序列的六种状态(详见第一篇题解),只要转移足够好就可以做到不重不漏

那么怎么转移呢。不同的状态可能会有相同的组成成分,要是在利用这相同组成成分转移时将两者都算了进去就会算重,所以可以利用最靠后的某种结构来转移

example.现在要转移*()*(),那么看似我们需要从*(),*()*()*,()**,()*()转移,但这样就会愉快地算重。所以就把最右边的()看作一个单位,它左边可以与*()相连,也可以与*()*相连,这样转移就没问题了

区间DP之一个人来回跑

关路灯属于同一种题。

  • 先断环为链,然后看数据范围,这显然是个区间DP,所以肯定会有 l,r 两维表示已经走完了的区间。

  • 走完了区间可能目前在左端,也有可能在右端,所以再设一维 [0/1] 表示目前在左端点或右端点。

  • 根据题意,不一定能取到区间内的所有熊,而能否取到与时间密切相关;数据量不允许将时间放进 DP 状态内(显然也不能离散化),所以可以像某次模拟赛的题那样将答案放进状态中

最后,状态就是 fl,r,k,0/1 表示走完 [l,r] 拿了 k 个熊目前在区间左/右端点花费的最少时间,时间复杂度 O(n3) 跑不满,完事儿

填表法&刷表法

填表法是用之前已经确定的 DP 状态确定现在的 DP 状态,比如石子合并,而刷表法是用现在已经确定的 DP 值更新可能由它转移的 DP 值。

在一些题目中,用刷表法会比填表法更加方便(需每个状态所依赖的状态对它的影响相互独立)。比如在这题中,因为该 DP 状态中包含答案,是否能 +1 需要额外判断,用刷表法转移就更加方便一些

矩阵加速DP

有一些 DP 的转移是以求和的方式转移的,这就说明所有的 DP 状态的值其实都是最开始初始化的那几个值贡献的,只不过是贡献次数不同。

矩阵加速就是利用这个东西,在快速幂(以及三次方)的时间复杂度内求出最开始初始化的每个值贡献的次数来快速计算最终的答案。

比如说,假设真正的 DP 数组滚动后是一维的,相关矩阵是二维的,矩阵第 i 行的 ai,j 可以理解为:转移到需要的状态 i 需当前的状态 j 贡献 ai,j 次。

以这道题为例,很容易列出状态转移方程(这个时候就不要想记搜了……),因为 n 的数据范围过大,就可以用矩阵加速。

这道题的矩阵是固定的,在有的题中矩阵要根据输入生成。

质因子状压

首先,300 以内有 62 个质数,可以利用状压维护质因子相关信息(比如CF1114F),往上就没办法直接状压了,比如这道题。

大概有这样一条性质:一个数的质因子最多只能有一个大于自己的算术平方根。在此题中,500 的数据范围内大于等于 23 的质因子最多出现一次,23 以内的质数只有 8 个,所以可以分组转移使得不会有相同大质因子的数在同一集合中(这题方案合法的充要条件为质因子集合不交)

具体地,具有相同大质因子的数要么都在集合 1 中,要么都在集合 2 中,要么都不在,开两个 dp 数组分别记录都在集合 1 \集合 2 中的方案数分别转移,再开一个 dp 数组记录全局的即可(需去重)


计数相关

状态怎么设呢,感觉会有一维代表“选不选”或是与相关性质有关的状态,然后转移的时候考虑这一维是怎样贡献的:是 u 自带的,还是 v 贡献的

线段树合并优化 DP

关于调试

调半天发现是线段树的 query 函数没返回值 [龙图问号]

第一次出错的时候就感觉是取模有问题,看了一圈都没看见,结果最后还真是有个地方忘取模了 [龙图疑惑]

首先这显然是树形 DP,因为答案和约束有关,所以状态中还要体现约束

然后有个性质:对于一些约束 (u1,v),(u2,v)…,若深度最深的 ui 约束条件被满足了,那么所有的约束条件都可以满足。状态的设计可以利用这个性质:设 fx,i 表示在 x 子树中满足所有被包含的约束条件,未被满足的约束条件(贯穿 x 节点)的 u 的最深深度为 i 的方案数。

考虑从子节点 vx 的转移(x 就是要和 v 一起用!)。若给边 (x,v) 染色,那么所有下端在 v 子树内的约束都可被满足,贡献即为 fx,i×j=0depxfv,j

若不给边 (x,v) 染色,那么状态中的 i 可能由 x 贡献,也有可能由 v 贡献,转移就是 fx,i×j=0ifv,j+fv,i×j=0i1fx,j (注意两个节点一起贡献 i 的不要算重)

这里有个求和号,可以用个 gx,i 表示 j=0ifx,j。最后的转移式就是 fx,i×(gv,depu+gv,i)+fv,i×gu,i1。那么,统计 gi,j 又成了问题。

同时发现,fx,i 是没法直接当数组开的,所以直接线段树启动,DP 的转移变成了线段树之间的加减乘除,也就是线段树合并

su,sv 分别表示父节点 DP 相关的前缀和以及子节点 DP 相关的前缀和。因为 gv,depu 是个定值,所以先用它给 sv 赋值,会改变的部分 gv,i,gu,i1 一边线段树合并一边加(注意 su 统计的是到 i1 的部分,sv 相反,所以一个是在转移后加,一个是在转移前加)。

然后就这样乱七八糟不知道为啥对地做完了。

连通性相关的计数DP

怎么做啊怎么做,和连通性有关是吧,先缩个点。缩完点后是树,每个节点内的非割边可以随便选,太好了开始跑树形 DP。

设状态 fu,0/1 表示 u 子树内不建/建军营并使得所有军营连通的方案数,钦定 u 子树外的点全都不选且绝对不选连接 u 的那条边。统计答案时,因为一定要建军营,所以 fu,1 会贡献;在该子树外还会有边的选择方案,所以它贡献时还要乘上子树外的边选择的方案数。

怎么转移呢怎么转移呢,如果不建军营那连接的那条边就可选可不选,也就是 Πfv,0×2 。那要是建军营,看目前有没有军营,有的话爱选不选,就是 fu,1×(fv,1+fv,0×2) ,要是没军营就要 v 子树贡献了,也就是 fv,1×fu,0

然后就乱七八糟不知道为什么不重不漏地做完了

posted @   还是沄沄沄  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示