[学习笔记]决策单调性优化 DP
引入
-
一类最优化 DP:
-
\[f_i={\min/\max}_{j=0}^{i-1}\{f_j+w(j+1,i)\} \]
-
利用 \(w\) 的特殊性质,可以做到 \(O(n\log n)\) 或 \(O(n)\) 的复杂度
第一类
特殊性质
- 设 \(f_i\) 的最优决策为 \(p_i\),则对于任意 \(i<j\) 有 \(p_i<p_j\)
优化方法一
-
考虑对于每个未计算出的 \(f\),维护其最优决策
-
即每算出一个 \(f_j\),就把那些取决策 \(j\) 更优的 \(f_i\) 的最优决策更新成 \(j\)
-
由定义可知,需要更新决策的 \(i\) 一定是一段后缀
-
考虑用一个栈维护决策序列,对于每个决策 \(j\) 维护一个区间 \([l,r]\) 表示 \(f_{l\dots r}\) 的最优决策为 \(j\)
-
当 \(f_j\) 计算出来的时候,先考虑栈顶的 \(l\),考查 \(f_j\) 能否更新 \(f_i\) 的最优决策
-
如果能就弹栈顶继续检查
-
否则在栈顶的区间 \([l,r]\) 中二分出一个最小的 \(i\) 满足 \(f_i\) 能被 \(f_j\) 更新最优决策
-
把 \(r\) 改成 \(i-1\),并把决策 \(j\) 压入栈,区间为 \([i,n]\)
-
\(O(n\log n)\)
优化方法二
-
上面的方法存在一定的局限性:\(w(j+1,i)\) 必须能快速求出来
-
当 \(w(j+1,i)\) 必须以 \(O(i-j)\) 的复杂度求出时,考虑另一种实现方式:分治
-
定义分治函数
solve(l, r, xl, xr)
表示 \(f_{l\dots r}\) 的决策在 \([xl,xr]\) 之间 -
取 \(mid=\lfloor\frac{l+r}2\rfloor\),求出 \(f_{mid}\) 的最优决策 \(m\)
-
然后递归到
solve(l, mid - 1, xl, m)
和solve(mid + 1, r, m, xr)
-
还是 \(O(n\log n)\)
-
需要注意实现姿势,避免复杂度爆炸,保证单次分治的复杂度为 \(O(r-l+xr-xl)\)
-
但这种优化方法也有局限性:转移必须是 \(g\rightarrow f\) 而不能是 \(f\rightarrow f\),即转移不能进行在同一个数组内
-
常用于分层 DP 中
第二类
特殊性质
-
\(w(j,i+1)-w(j,i)\) 和 \(w(j+1,i+1)-w(j+1,i)\) 的大小关系对于所有的 \(i,j\) 都一样,即满足四边形不等式
-
换句话说,对于任意的两个决策 \(j<k\),存在一个 \(x\) 满足 \(i\le x\) 时 \(j\) 比 \(k\) 优,\(i>x\) 时 \(j\) 比 \(k\) 劣
-
或者 \(i\le x\) 时 \(j\) 比 \(k\) 劣,\(i>x\) 时 \(j\) 比 \(k\) 优
优化方法
-
若 \(i\le x\) 时 \(j\) 比 \(k\) 优,\(i>x\) 时 \(j\) 比 \(k\) 劣,则这和前面提到的第一类是等价的,可以直接用第一类的优化方法
-
但这里讲述另一种方法
-
考虑维护一个单调队列,储存对当前的 \(i\) 和 \(i\) 之后可能最优的决策
-
每当计算出一个 \(f_l\) 之后,检查队尾的两个决策 \(j,k\) 是否会因为决策 \(l\) 的加入而使得 \(k\) 变成不可能最优的决策
-
根据定义里提到的特殊性质,我们只需二分出一个最大的 \(i\) 满足决策 \(k\) 比 \(l\) 优,然后判断这时 \(j\) 是否比 \(k\) 优,是则 \(k\) 应该被从队尾弹出
-
这样一直弹栈直到 \(k\) 可能最优为止
-
考虑取 \(f_i\) 最优决策,可以证明去除了无用的决策之后,队列内剩下的决策对应 DP 值是单峰的,故从队首不断出队即可找到最优决策
-
\(O(n\log n)\)
-
实际上判断是否弹队尾,有时可以使用特殊的方法代替二分来实现 \(O(1)\) 判断
-
如斜率优化的本质就是这种形式的决策单调性优化
-
若 \(i\le x\) 时 \(j\) 比 \(k\) 劣,\(i>x\) 时 \(j\) 比 \(k\) 优,则最优决策要从队尾取,这时把队列改成栈即可