线段树优化dp
当递推的时候,整个区间的变化都是一样的,就可以考虑用线段树加速dp递推。
单调队列优化dp
对于某一个 i 进行 dp 时,其左边的最优决策点假如是 j,如果 j 随着 i 的增长是单调递增的,那么可以用单调队列优化:队首是最优决策点,然后每次把不符合条件的队首弹出,把更劣的队尾弹出,然后把当前决策点加入队尾。这样保证每个点入队一次出队一次,复杂度为 O ( n ) O(n) O(n) 。
- 比如对于这道题 烽火传递 :
有 n 个烽火台,每个烽火台点亮的代价为 a[i],连续 m 个烽火台至少要有一个点亮,问最小代价。
设 f i f_i fi 表示点亮第 i 个烽火台的最小代价,显然有 f i = min j ≥ i − m f j + a i f_i=\min\limits_{j\ge i-m}f_j + a_i fi=j≥i−mminfj+ai 。而且这里的 j ,也就是决策点, 一定是单调递增的,因为如果存在一个地方是递减的,那么之前的那个 i 做决策时也应该选择这一个 j,而不应该选择更大的 j 。或者可以这样想:j 越大说明后面的选择越宽裕,而优先队列维护的是对于当前的 i 合法的决策点,更新这个队列时把更劣的踢出去,然后把 f i f_i fi 加入队尾。
观察这个式子 f i = min j ≥ i − m f j + a i f_i=\min\limits_{j\ge i-m}f_j + a_i fi=j≥i−mminfj+ai 可以发现,对于每个 i 它的决策点 j 只作用于左边那一块,右边的 a i a_i ai 不受 j 影响,这是为什么可以用单调队列优化的原因。
分治优化dp
如果右边的 a i a_i ai 变成了 a ( i , j ) a(i,j) a(i,j) ,单纯地单调队列就优化不了了,因为 a 这一部分处于不断变化之中。对于这种情况: f i = min 0 ≤ j < i { g j + a ( i , j ) } f_i=\min\limits_{0\le j<i}\{g_j+a(i,j)\} fi=0≤j<imin{ gj+a(i,j)} ,而且满足决策单调性,要么用二分栈,不过我更喜欢用分治去做。
因为满足决策点调性,假如当前我要处理的是 f [ l , . . . , r ] f[l,...,r] f[l,...,r],并且可能的决策区间为 [ L , R ] [L,R] [L,R] ,那么我们可以定义一个 m i d = ( l + r ) / 2 mid=(l+r)/2 mid=(l+r)/2,然后在 [ L , m i d ] [L,mid] [L,

本文深入讲解了DP算法的四种优化技巧:线段树优化、单调队列优化、分治优化和斜率优化,通过实例详细解析了每种优化方法的应用场景和实现过程。
最低0.47元/天 解锁文章
5109

被折叠的 条评论
为什么被折叠?



