「学习笔记」整体 dp

适用范围

对于一些只有状态上的值不同而转移方程完全相同的 dp 可以考虑使用这个 trick。

一般用线段树合并维护,当前点 \(x\) 的线段树的叶子节点下标 \(y\) 的位置的权值,是第 \(y\) 次 dp 到 \(x\) 这里的权值。

例题

[NOIp 2018] 保卫王国

转移方程为:

\[\begin{aligned} f_{x, 0} &= \sum_{y \in \mathrm{son}_x} f_{y, 1}\\ f_{x, 1} &= p_x + \sum_{y \in \mathrm{son}_x} \min(f_{y, 0}, f_{y, 1}) \end{aligned} \]

用线段树合并维护 \(m\) 次询问,那么一个 a x b y 的询问相当于线段树上的单点修改,可以用矩阵维护。

在向父亲合并时需要乘上以下矩阵 \(\begin{bmatrix} \infty & 0\\0 & 0 \end{bmatrix}\) 以方便合并:

\[\begin{bmatrix} f_0 & f_1 \end{bmatrix} \times \begin{bmatrix} \infty & 0\\0 & 0 \end{bmatrix} = \begin{bmatrix} f_1 & \min(f_0, f_1) \end{bmatrix} \]

代码要比正常的动态 dp 短很多。code

[九省联考 2018] 秘密袭击

前面的推导部分不再赘述。

用生成函数的方式表示出转移方程。

\[F_{i, j} = x ^ {[v_i \geq j]} \prod_{p = 1}^{|s|} (F_{s_p, j} + 1) \]

先枚举一个数字 \(p\),设 \(f_{i, y}\) 表示 \(F_{i, y}(x)\) 这个生成函数在 \(x = p\) 时候的点值,为了方便枚举答案,设 \(g_{i, y}\) 表示 \(f_{i, y}\) 的子树和。

用线段树合并维护 \(f\)\(g\),于是需要支持这两个操作:

  • \(f\) 整体 \(+ 1\) 和整体乘上一个数。
  • \(f\) 加到 \(g\) 上。

考虑定义一个变换 \((a, b, c, d)\) 使得 \((f, g) \to (af + b, cf + d + g)\),那么两个变换 \((a_1, b_1, c_1, d_1)\)\((a_2, b_2, c_2, d_2)\) 合并会变成 \((a_1a_2, a_2b_1 + b_2, c1 + c_2a_1, c_2b_1 + d_1 + d_2)\),这样就可以很好维护了,只需要最后再插值回来即可。

这个标记应该也可以用矩阵维护。code

[NOI2020] 命运

这里

posted @ 2020-08-13 09:32  xgzc  阅读(434)  评论(4编辑  收藏  举报