DP 用于解决多阶段性决策性问题,方法是每个阶段分开转移,各个阶段转移是独立的,不会影响到其他阶段的转移。因此,整个 DP 的过程其实就是原始数据(即边界)顺次按照阶段转移,最终成为答案。
矩阵代表着一种线性变换,矩阵的乘法其实就是变换的合成,所以我们可以将 DP 每个独立阶段的转移抽象为一个矩阵,原数据抽象(边界)为一个向量,转移的过程就是向量依次与矩阵相乘的过程。
注意当矩阵二元运算具有结合律和交换律时,矩阵的乘法也具有结合律。所以我们可以先将所有转移过程相乘,合并为同一个矩阵,代表着整个转移过程,然后再直接将数据与该矩阵相乘。
这样的好处非常明显:每次更换初始值时不必再重新将数据再一步一步转移,而是直接乘一遍就好了。
而且我们可以用线段树(甚至前缀和,如果有逆元)来维护矩阵的乘积,这意味着现在天生支持修改矩阵,也就是转移步骤,可以在 \(O(1)\) 之内求出修改转移后的新的答案。
这就是动态 DP,它支持多次修改转移过程并求答案。
例题
Luogu P4719 【模板】"动态 DP"&动态树分治
先考虑不带修的做法。其实就是 Luogu P1352 没有上司的舞会,设状态 \(f_{i,0/1}\) 代表第 \(i\) 个节点选或不选时其子树的答案。转移为
\(\begin{aligned}
f_{i, 0} = \sum\max \{f_{j, 0}, f_{j, 1}\}\\
f_{i, 1} = w_i + \sum f_{j, 0}
\end{aligned}\)
修改时,只有点 \(x\) 至点 \(1\) 的路径上的点的 \(f\) 值会更新,于是我们只需要从 \(x\) 节点往上爬,更新这条链上的 \(f\) 值即可。
但这种方法时间复杂度没有保证(题暴力能过),因为树的深度没有保证。
其实每次修改时,只是一个地方的转移方式改变了一点(就 \(w_i\) 变成了新的值),我们却要将整条链所有转移都重算一遍,这就浪费了时间。这种情况和动态 DP 能优化的情况刚好相同,因此尝试使用动态 DP 进行求解。
但是现在的转移方式并不能抽象成一个矩阵,因为每个点上的转移涉及到其所有子节点,矩阵的维度会非常大。