决策单调性优化dp学习笔记
点的第一个省选级算法,算是一个很好的过渡。
决策单调性,也称四边形不等式优化dp。主要适用于转移式子大概长这样的时候:
\(f_i = \min/\max\{f_j + w(j,i)\}\),其中\(w(j,i)\)满足四边形不等式。
四边形不等式
当\(a\le b\le c \le d\)时,若存在$ w(a,c) + w(b,d) \le w(a,d) + w(b,c)$ ,则称\(w\)满足四边形不等式。
用的更多的一般是\(w(j,i) + w(j+1,i+1) \le w(j,i+1) + w(j+1,i)\),此时\(j \le i\)。
决策单调性
当上述条件满足时,若\(f_i\)是从\(f_j\)转移过来的,则\(f_{i+1}\)从\(f_j\)转移过来,一定不劣于从\(f_{j-1}\)转移过来。
证明:
已知\(f_j = f_j + w(j,i) \le f_{j-1} + w(j - 1, i)\),\(j < i\),\(w\)满足四边形不等式
求证\(f_j+w(j,i+1) \le f_{j-1} + w(j-1,i+1)\)
由于\(w(j-1,i) + w(j,i+1) \le w(j,i) + w(j-1,i+1)\),所以把这个式子和已知式子分别加起来,不等号方向不变,则有:
\(f_j + w(j,i+1) \le f_{j-1} + w(j-1,i+1)\)
证完。
所以我们注意到,对于每个\(f_i\),它的最优决策点一定是单调不降的。这就是决策单调性。
实现
有两种可行的代码实现,二分队列和分治,各有优劣,先讲二分队列。
二分队列
其实本质上更类似单调队列,只是维护的过程中要用到二分。
设\(g_i\)代表\(i\)的最优决策点,则\(g\)的变化过程类似于:
11111111 -> 11222222 -> 11222233 -> ……
注意到这里的每一个数值都“统治”着一个区间。
且每次加入新数的时候,它的统治范围一定是从中间某个位置\(k\)到队尾的。
所以我们可以维护一个队列,记录每一个数值i,它的左端点和它的右端点。
如果队头右端点小于当前i就把它清出去。
每次入队的时候,二分的去确定\(k\)的位置,调整上一个元素(队尾)的右端点,再把当前元素插进队尾。
注意有些元素可能不会入队,需要处理一下。
优势在于容易理解,复杂度稳定在\(O(log_n)\),劣势是比较难写,细节有点多,而且对于无法\(O(1)\)计算\(w\)的情况会比较麻烦。
分治
个人感觉难想但好写。
用\(solve(s,t,l,r)\)表示当前处理\(s\sim t\)这一段区间,且区间内所有点的最优决策点都在\(l \sim r\)之间。设\(mid\)为\(s \sim t\)的中点,则可以从\(l \sim r\)逐一枚举找出\(mid\)的最优决策点,记为\(u\),并更新\(f_{mid}\)。
此时由决策单调性可知,\(s \sim mid-1\)的最优决策点一定在\(l \sim u\)之间,右侧同理。
递归分成\(solve(s,mid-1,l,u)\)和\(solve(mid+1,t,u,r)\)即可。
此时的复杂度是\(O(nlog_n)\),因为一共会递归\(log\)层,每层从\(l\)到\(r\)枚举,会把$ 1 \sim n$ 都枚举一遍,是\(O(n)\)的。
但上述方法只能处理类似\(f_i = \min\{a_j + w(j,i)\}\)的情况,因为这时要求对于任意一个位置\(i\),前面的\(f\)都没求的时候,可以直接求出\(i\)的值。
如果遇到\(f_i = \min\{f_j + w(j,i)\}\),就不能这么办了,需要cdq分治。
cdq分治的本质就是先处理出左区间的信息,再用左区间的信息去更新右区间。
对于每一个点,它会不停地被别的区间更新,然后再递归下去。
直接在外面套一个cdq就好了。复杂度\(O(nlog_n^2)\)
分治的优点是简单好写,同时可以复杂度不变的处理一些\(w\)不能\(O(1)\)求出的东西。
这里详细讲一下,例如,转移式子是\(f_i = \max\{a_j + w(j,i)\}\),其中\(w(j,i)\)代表这一段区间内不同的数的个数。
证明
这个东西是满足反向的四边形不等式的,浅证一下:
求证:\(w(j,i)+w(j+1,i+1) \ge w(j,i+1) + w(j+1,i)\)。
有两种可能。
第一,\(w(j,i) = w(j,i+1)\),说明\(i+1\)这个数在\(j \sim i\)里出现过,若\(i+1\)的前驱刚好是\(j\),则有\(w(j+1,i+1)=w(j+1,i)+1\),否则有\(w(j+1,i+1)=w(j+1,i)\),成立。
第二,\(w(j,i) = w(j,i+1)-1\),即\(i+1\)没出现过,那么此时一定有\(w(j+1,i+1)=w(j+1,i)-1\),成立。
证完。
然后我们发现\(w(j,i)\)无法\(O(1)\)求出,二分队列或许可以上个什么数据结构之类的,但会很麻烦,但分治完全不会出现这种问题,因为我们可以边枚举边求\(w\),时间复杂度不变。
完结撒花!