Loading

[专题总结] DP记录 II

Tree Dp

Range Dp

扩展矩阵乘-ddp

扩展矩阵乘是把矩阵乘法的加法,乘法重新定义,由于需要结合律,唯一需要满足的就是 “乘法” 对 "加法" 有分配率。

常用在求最值的 dp 中, 把乘法定义成 +, 把加法定义成 \(\min, \max\) ,单位矩阵是主对角线全是 \(0\),其他地方全是 \(\pm \infty\)

NOI模拟7.22 C

我们首先考虑 \(k=1\) 怎么做,求 \(s \rightarrow t\) 经过 \(a\) 条边的最短路,定义 \(dp_{s,t,x}\) 代表 \(s \rightarrow t\) 经过 \(x\) 条边的最短路,转移类似 Floyd 枚举中转点从 \(dp_{s,u,k}+dp_{u,t,x-k}\) 来更新,发现更新类似矩阵的形式。

我们把最外面一层拿出来,那么暴力转移就可以每次矩阵 \((+,\min)\) 乘邻接矩阵,然后可以快速幂优化。

对于矩阵加速题,处理多询问的套路就是处理出来 \(2^k\) 的值,然后每次询问向量乘矩阵。

现在再考虑 \(k\) 怎么办,我们让矩阵的一个元素是 \(k\) 个值分别代表前 \(k\) 小 (矩阵的每个地方不一定填一个 int, 不要思维定式,填的元素只需要保证可以转移就行)。

我们枚举 \(u\) 之后得到 \(A_{[1,n],[1,15]},B_{[1,n],[1,15]}\) ,我们的目的是找到前 \(k\) 小的 \(A_{u,j}+B_{u,k}\)

普通的矩阵乘得到一个元素的值需要花费 \(O(n)\) 复杂度,这个东西是二维状态极值问题,每维上分别有单调性,直接套用超级钢琴的做法,配合线性建堆,可以做到 \(O(n+klogk)\) 的复杂度。

具体的,初始我们把 \(\{A_{u,0}+B_{u,0},u, 0, 0\}\) 这个四元组入堆,关键字是第一维,分别代表最短路值,点,A的下标,B的下标。

取出堆顶的时候我们把第三维加一入堆,为了保证到达每个点只有一次,我们可以让每个店都被字典序最小的路径走到,当且仅当第三维是 \(0\) 的时候我们把第四维加一入堆,这样我们最多取出 \(k\) 个元素,复杂度 \(klogk\)

Dp 套 Dp

省选模拟15 A

题目给定了一些未知位置,如果对于一个已知所有位置的串,我们可以去找性质快速判定是否合法,那么一般是根据性质直接 \(DP\) 计数,但是如果我们通过 \(DP\) 才能判断其是否合法,那么一般就需要使用 \(DP\)\(DP\) 进行计数。

先不扯那么多了,考虑如何判断一个已知串是否合法。

发现一个性质,每次只会改变一个前缀,我们可以设计 \(dp_{i,0/1}\) 代表长为 \(i\) 的前缀,能不能变成 \(0/1\) ,最后检查 \(dp_{n,1}\) 就是答案。

转移很简单,枚举上一次是在哪里合并的,也是 DP 的经典套路:枚举最后一次操作,变成独立的子问题,这个简单dp不是重点。

发现上面的 dp 是每次划分一段一段的,转移是 \(O(n)\) 的。这种 DP 有经典的优化手段:枚举当前是否划分一段,即可做到 \(O(1)\) 转移

暴力的想法就是记录上一个划分点 : \(f_{i,j,0/1}\) 代表 当前在 \(i\) ,上一次在 \(j\) 划分, \(j\) 之前被压缩成了 \(0/1\) ,是否可行。

转移枚举当前点划不划分,转移到 \(f_{i+1,i,balabal},f_{i+1,j,0/1}\)

发现虽然转移 \(O(1)\) 了,但是状态增加了,考虑寻找性质压缩状态。

不管上一次是在哪里划分的, \([j::i]\) 的字符串最多形成 \(4\) 种自动机。

\(0 -> 0, 0 -> 1, 1 -> 0, 1 -> 1\) ,那我们记录前 \(i\) 个点,每种自动机是否存在即可,最后检查 \(f_{n,{a_n -> 1}}\) 是否存在,转移考虑一次转移两个字符,枚举划不划分即可。

现在已经可以判断合法了,考虑计数,发现前 \(n\) 个点,我们唯一能区分不同方案的就是他当前四种自动机是否存在,那么就开 \(2^4\) 记录一下每种自动机的存在状态,和上面一样去转移即可。

DP 套 DP,内层 DP 用来判断合法,如果内层 DP 数组的值相同,那么两种方案就等价,根据这个,把内层DP的值记录到状态里面,统计每种内层数组的方案数即可。

Dp优化

posted @ 2022-05-20 07:08  Soresen  阅读(43)  评论(0编辑  收藏  举报