DP优化方法
斜率优化
这个东西并不难
就是求形如 \(kx\pm b\) 的最大值或者最小值,一般来说,设整个柿子为 \(b\) ,通过移项来处理就可以了,取 \(\min/\max\) 分别对应下 / 上凸壳,找值相当于求固定斜率对于这个凸壳的切点
现在着重精力来看一下这个斜率的柿子
对于DP 而言,这里要求加入一些点,同时进行查询,这里分为三种情况来讨论:
- 加入的点的横坐标单调,而且直线的斜率单调
如果加入的顺序和直线在凸壳上切点的增长方向相同,就可以直接单调队列来做
- 横坐标单调,斜率不单调
这里也不难,只要二分一下单调栈就可以了,上面的方向要是冲突也可以这么做
- 横坐标不单调
这就麻烦了
横坐标要是不单调,那就变成了个动态凸壳,主流的有四种做法,这里介绍 CDQ
网上一直没有找到较好的解释博客,这里推荐去这题的题解区
我们发现,如果把整个修改和查询抽象成一个序列,那可以把序列的左半边,的答案先算出来,然后根据答案建出凸壳,然后去更新右半边的答案
这就是 CDQ 的基本流程了,不难写,复杂度两只 \(\log\)
同时,李超线段树虽然不太可以维护凸包,但只要进行一点变化,就可以来维护这类斜率优化问题,复杂度和CDQ 一样,可以参考这个
决策单调性
这里分为几种:
1D单调性
形如 \(f_i=\min/\max\{f[j-1]\}+val(i,j)\)
这种东西要是有单调性,那也没有我已知的方法做到线性,就能二分枚举中间点的决策点来处理
当然,二分队列也是可以的,接下来介绍一下这种方法
在队列中,维护一个三元组 \([s,l,r]\) ,代表扫到当前,这个状态在区间 \([l,r]\) 是最佳的方案,在队列里,元素按照决策顺序从小到大排列
假设当前已经到了位置 \(i\)
将队头的超时的决策去掉
来到队尾,先更新队尾节点的左端点,然后比较一下,如果这个点在其所有的决策空间内都被这个点吊打,那就把这个点给去掉
然后,二分出队尾元素与当前元素的决策交界点,将当前元素压入
一般来说,最好先清空无用决策,再进行二分,不然容易让自己的二分假掉,不过好像也没影响
假如价值的计算是一个初等函数,可以借助一些数学方法做到线性
2D非区间DP
形如 \(f_{i,j}=\min/\max\{f_{i-1,k-1}\}+val(i,k)\)
这个就是标准的四边形不等式理论了,对于这个转移,自然是有单调性的,具体来说 \(M_{i,j}\in [M_{i-1,j}\,,M_{i,j+1}]\)
细节来说,枚举第二维的时候,需要倒序来做
2D区间DP
这个就是四边形不等式了,直接看 OI-Wiki 就可以了
浙公网安备 33010602011771号