线头 DP 学习笔记
线头 DP 学习笔记
线头 DP 主要是指维护一些左闭右开的线段的 DP,在这里可能右端点没有确定,只确定了左端点,每次操作可以延伸一个线段,或者确定一个右端点
找不到板子了
直接例题引入
CF626F
有一个长度是 $ n $ 的数组 $ a $,分成若干组,极差总和不超过 $ k $,求方案数
这个题我们先考虑朴素 DP
设 $ dp_{i, j, k} $ 表示前 $ i $ 项选了 $ j $ 个,极差是 $ k $,但不能确定选到哪一组,所以也不能记录极差
于是记录每组,就是 $ dp_{i, j, k} $,表示前 $ i $ 个,选了 $ j $ 组,当前极差是 $ k $
但是转移需要枚举加入哪一组,这样也没法转移
所以引入线头 DP
我们先做一步转化,我们先按照 $ a_i $ 从小到大排序,然后转化求极差的部分
我们在一组中插入 $ a_i $,上一位是 $ a_j $,那么极差就要加上 $ a_i - a_j $,自行理解
本题中无法记录上一个数 $ a_j $,所以我们直到确定了右端点再加入贡献即可
然后把刚刚的 DP 第二维 $ j $ 改成表示当前有 $ j $ 组还没有确定右端点
这样可以线头 DP
考虑转移,我们可以做以下操作:
-
延伸一个右端点
-
确定一个右端点
-
新开一个左端点
-
自己做一组
转移分别如下:
- 延伸一个右端点
$ dp_{i, j, k} += dp_{i - 1, j, k} \times j $
- 确定一个右端点
$ dp_{i, j, k} += dp_{i - 1, j + 1, k + a_i} \times (j + 1) $
- 新开一个左端点
$ dp_{i, j, k} += dp_{i - 1, j - 1, k - a_i} $
- 自己做一组
$ dp_{i, j, k} += dp_{i - 1, j, k} $
然后我们做完了