四边形不等式优化
定义
假设有 \(p_{1}\leqslant p_{2}\leqslant p_{3}\leqslant p_{4}.\)
则 \(c_{p_{1},p_{3}}+c_{p_{2},p_{4}}\leqslant c_{p_{1},p_{4}}+c_{p_{2},p_{3}}\) 被称为四边形不等式。
假设一个问题满足四边形不等式,那么它的决策点有单调性。
Proof:
假设有如下问题 :现在有一个序列,我们要将其分割开来,分割一段 \([l,r]\) 的代价是 \(c_{l,r}\),求最小代价。
设 \(F_{i}\) 表示将前 \(i\) 个位置分割完毕的最小代价,显然有暴力转移 :
\[ F_i=\min\limits_{j\lt i}\{F_j+c_{j,i}\} \]设 \(F_{i}\) 的决策点为 \(p_{i}.\) 假设存在 \(x\gt y,p_{x}\lt p_{y}.\)
根据最优决策的定义写出这个位置的转移式 :
\[ F_x=F_{p_x}+c_{p_x,x}\leqslant F_{p_y}+c_{p_y, x} \]有 \(p_{x}\lt p_{y}\lt y\lt x\),根据四边形不等式得到 :
\[ c_{p_x,y}+c_{p_y,x}\leqslant c_{p_y,y}+c_{p_x,x} \]两不等式相加,得到 :
\[ F_{p_x}+c_{p_x,y}\leqslant F_{p_y}+c_{p_y,y} \]与前文矛盾,故不存在 \(x\gt y,p_{x}\lt p_{y}\),即满足决策单调性。
需要注意的是,只有最小化问题才能通过四边形不等式判定决策单调性。
区间形式
在实际做题中,我们经常遇到这样的 \(\rm DP\) 方程 :
\[ f_{i,j}=\min\limits_{i\leqslant k\lt j}\{f_{i,k}+f_{k+1,j}+w_{i,j}\} \]我们考虑将四边形不等式推广到二维形式。
定理 \(1\) :若 \(w\) 满足四边形不等式,并且对于任意 \(a \leqslant b\leqslant c\leqslant d\),有 \(w_{a,d}\geqslant w_{b,c}\),则 \(f\) 也满足四边形不等式。
定理 \(2\) :设 \(p_{i,j}\) 表示 \(f_{i,j}\) 的决策点,若 \(f\) 满足四边形不等式,则对于任意 \(i\lt j\),有 \(p_{i,j-1}\leqslant p_{i,j}\leqslant p_{i+1,j}.\)
例题 :[NOI1995] 石子合并
转移技巧
有单峰性
这个性质结合决策单调性有均摊转移复杂度 \(\Theta(1)\) 的做法 :
记录一个指针表示当前的决策点,由于决策单调性所以它不会往回跳。进入每一层之后如果后面的决策点更优就跳到后面的决策点,根据单峰性这样一定不会漏掉解。
跳的次数是状态级别的,故转移均摊 \(\Theta(1).\)
仅有相邻层之间转移
这是一类特殊的二维 \(\rm DP\),仅有相邻层之间的转移,没有同层之间的转移,同时满足决策单调性。
一般这种 \(\rm DP\) 的时间复杂度是 \(\Theta(n^{3})\) 的,每次转移需要枚举前一层的所有点。
我们发现一个性质,在同一层中,先枚举哪一个是无关紧要的,因为同一层之间不会发生转移。
于是可以考虑分治,先转移 \(mid\),得到其最优决策为 \(p\),然后就可以将区间划分开,\([l,mid)\) 和 \((mid,r]\) 分别对应 \([tl,p]\) 和 \([p,tr].\)
这样分治时间复杂度 \(\Theta(n\log n).\)
例题 :[SDOI2016] 征途
贡献难算
首先有例题 :存在一个长度为 \(n\) 的序列,要将它划分成 \(k\) 段,每段的价值被定义为不同的元素个数,要求最大化贡价值和。
数据范围:\(n\leqslant 3.5\times 10^{4},k\leqslant 50.\)
首先有一个 \(\Theta(n^{3k})\) 的暴力 \(\rm DP\),设 \(dp_{i,j}\) 表示当分到 \(i\) 时已经分了 \(j\) 段的最大价值,有转移式 :
\[ dp_{i,j}=\max\limits_{k\lt i}\{dp_{k,j-1}+cnt_{k+1,i}\} \]其中 \(cnt_{l,r}\) 表示从 \([l,r]\) 中不同颜色的个数,单次计算需要 \(\Theta(n).\)
我们发现只在相邻层之间发生转移,并且满足决策单调性(直观理解就是分得越多越容易亏),于是可以使用之前提到的分治法。
这样看起来是优化到 \(\Theta(n^{2k}\log n)\),但我们考虑计算贡献的具体过程。我们每次只会计算 \(dp_{mid}\) 的值,每次询问一个区间 \([i,mid]\) 的不同元素个数,可以考虑固定右端点移动左端点,容易发现移动次数是当前的分治区间长度,于是总移动次数不会超过 \(n\log n\),故时间复杂度实际上为 \(\Theta(nk\log n).\)
常用算法
斜率优化
假设 \(\rm DP\) 方程长成这种形式 :
\[ dp_i=\max\limits_{j\lt i}\{dp_j+(i)'+(i)(j)+(j)'+C\} \]即贡献为一个仅与 \(i\) 有关的式子加上一个仅与 \(j\) 有关的式子加上一个与两者都有关的乘积形式再加上一个常数,那么可以使用斜率优化。
我们发现 \(dp_{i},(i)',C\) 都与决策点的选择无关,于是可以把它们看作常数,将仅与 \(j\) 有关的式子放在一边,可以得到方程 :
\[ dp_j+(j)'=-(i)(j)+dp_i-(i)'-C \]我们发现这是一次函数的形式,考虑构造平面,平面上有一些点,形如 \(((j),dp_{j}+(j)').\) 我们发现,如果用一条斜率为 \(-(i)\) 的直线经过某个点,那么截距为 \(dp_{i}-(i)'-C.\) 由于我们要最大化 \(dp_{i}\),等价于最大化这个截距,所以用这根斜率为 \(-(i)\) 的直线从上到下平移,第一个碰到的点就是决策点。
于是现在问题就变成了维护一个凸包,我们发现有三种情况 :
- 当加入点按照横坐标单调递增的顺序,并且询问点单调递增时,可以直接维护单调队列,加入点对比队尾斜率,取答案从队首即可。
- 当加入点按照横坐标单调的顺序时可以维护一个单调队列,每次加入时对比斜率,取答案二分。
- 当加入点无序时直接用平衡树
(std :: set)维护,用lower_bound查找插入点,然后向左右两边依次弹出,取答案也使用lower_bound。
例题 :[SDOI2016] 征途
二分队列
若 \(\rm DP\) 方程形如 :
\[ dp_i=\min\limits_{j\lt i}\{dp_j+w_{j+1,i}\} \]根据决策单调性的推论,任何两个点 \(i,j(i\lt j)\) 之间都存在一个点 \(k\),在 \(k\) 之前一段转移点为 \(i\),在 \(k\) 之后某一段转移点为 \(j.\)
我们发现如果能快速计算 \(w_{i,j}\),那么就能 \(\Theta(\log n)\) 计算两个点 \(i,j\) 之间的决策分界点。
我们发现所有相邻决策点的分界点可以用单调队列维护,具体来说 :
- 求当前的最优决策时判断一下队首和队次首谁更优,若队首最优则决策点为队首,否则决策点为队次首,并且将当前队首弹出。
- 加入一个点时判断它是否能比队尾更快地替换掉队次尾,若能,则弹出队尾,重复操作。
这样就可以快速地维护相邻点的决策分界点了。
时间复杂度 \(\Theta(n\log n).\)
例题 :[NOI2009] 诗人小G
二分栈
有些题可能会有这样的奇怪性质 :每个决策点只会被自己前面的点反超。
我们发现某个决策点会经历这样的过程 :一开始就比前面的优(否则就相当于一开始就被别人反超了),然后在最优决策的地方呆一会儿,最后被某个点反超。
严格来说这根本不算决策单调性,但是仍然可以用二分栈来维护,因为两点的优劣仍旧可以 \(\Theta(\log n)\) 对比。具体来说 :
- 加入一个点时,若其比堆顶劣,则直接扔掉,若其比堆顶优,则留下。
- 每一轮判断一下堆次顶是否比堆顶优,优则将堆顶弹出。
这样堆顶就一直是当前转移的决策点。
例题 :\(\rm [POI2011]Lightning\ Conductor\)
习题
[NOI1995] 石子合并
首先有暴力转移 :
\[ dp_{l,r}=\min\limits_{i\leqslant k\lt j}\{dp_{i,k}+dp_{k+1,j}+w_{i,j}\} \]记录前缀和 \(sum\),这里 \(w_{i,j}=sum_{j}-sum_{i-1}.\)
\(w\) 显然满足四边形不等式和包含单调,于是考虑四边形不等式优化。
然后就直接设 \(p_{i,j}\) 表示 \(dp_{i,j}\) 的转移点,成功转移的时候更新,枚举 \(dp_{i,j}\) 断点的时候只需要枚举 \([p_{i,j-1},p_{i+1,j}]\) 即可。
时间复杂度 \(\Theta(n^{2}).\)
[SDOI2016]征途
首先易知,设每一天走的长度为 \(d\),则答案为 :
\[ m\sum_{i=1}^m(d_i-ave)^2=m\sum_{i=1}^md_i^2-\left(\sum_{i=1}^md_i\right)^2 \]容易观察到此题本质上是在求 \(\left(\sum_{i=1}^{m}d_{i}\right)^{2}_{\min}\),于是设 \(f_{i,j}\) 表示当前已经考虑到第 \(i\) 段,当前已经分成了 \(j\) 段的最小 \(\sum_{p=1}^{j}d_{p}.\) 枚举转移点,容易得到转移方程 :
\[ f_{i,j}=\min\limits_{k\lt i}\{f_{k,j-1}+(s_i-s_k)^2\} \]易证 \(w_{i,j}=(s_{j}-s_{i})^{2}\) 满足四边形不等式,所以该转移方程满足决策单调性。我们还发现转移方程只在相邻层之间转移,所以可以使用分治转移。
时间复杂度 \(\Theta(n^{2}\log n).\)
还有斜率优化的做法,注意到转移方程是可以变形的 :
\[ f_{i,j}=f_{k,j-1}+(s_i-s_k)^2 \]\[ \iff f_{i,j}=f_{k,j-1}+s_i^2-2s_is_k+s_k^2 \]\[ \iff f_{k,j-1}+s_k^2=2s_i\cdot s_k+f_{i,j}-s_i^2 \]易知插入点横坐标有序,询问斜率也有序,所以可以直接使用单调队列维护,每一层分开转移。
时间复杂度 \(\Theta(n^{2}).\)
[P5574]任务分配问题
非常套路的分治 \(+\) 决策单调性优化 \(\rm DP.\)
首先定义 \(w_{i,j}\) 表示 \(i\sim j\) 的顺序对个数,设 \(f_{i,j}\) 表示当前已经考虑到第 \(i\) 个任务,将他们分成 \(j\) 段的最小顺序对数量之和,易得转移方程 :
\[ f_{i,j}=\min\limits_{k\lt i}\{f_{k,j-1}+w_{k+1,i}\} \]对于任意 \(a\leqslant b\leqslant c\leqslant d\),使用容斥易证 \(w_{a,c}+w_{b,d}-w_{b,c}\leqslant w_{a,d}\),故 \(w\) 满足四边形不不等式。进一步的,\(f\) 的转移满足决策单调性。
有了决策单调性,我们就可以分治转移,同时令人惊喜的是,转移时需要遍历一段连续的区间并计算每一个位置的贡献,于是用莫队和 \(\rm BIT\) 维护一下就好了。
时间复杂度 \(\Theta(nk\log^{2n}).\)
