「学习笔记」整体 dp

适用范围

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

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

例题

[NOIp 2018] 保卫王国

转移方程为:

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

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

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

[egin{bmatrix} f_0 & f_1 end{bmatrix} imes egin{bmatrix} infty & 0\0 & 0 end{bmatrix} = egin{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) o (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

原文地址:https://www.cnblogs.com/cj-xxz/p/13494560.html