【引入】
有些$DP$方程可以转化成$f[i]=f[j]+x[i]$的形式,其中$f[j]$中保存了只与$j$相关的量。这样的$DP$方程我们可以用单调队列进行优化,从而使得$O(n^2)$的复杂度降到$O(n)$。
但像这样的方程:$dp[i]=dp[j]+(x[i]-x[j])×(x[i]-x[j])$。如果把右边的乘法化开的话,会得到$x[i]×x[j]$的项。它不能分解为只与$i$或$j$有关的部分。若用单调队列优化方法就不好使了。
这里学习一种新的优化方法,叫做斜率优化。
【例题】HDU 3507 print artical
【题目大意】
输出$N$个数字$a[N]$,输出的时候可以连续的输出,每连续输出一串,它的费用是 “这串数字和的平方加上一个常数$M$”。其中$N≤500000$。
【例题分析】
对于这样一个题目,我们先规定以下变量:
- $dp[i]$:输出到$i$的时候最少的花费
- $sum[i]$:从$a[1]$到$a[i]$的数字和。
于是方程就是:$$dp[i]=dp[j]+M+(sum[i]-sum[j])^2$$
很显然这个$DP$式时间复杂度为$O(N^2)$。题目的数字有$500000$个,很明显,若不对这个$DP$式加以修饰,是一定会超时的。
那么该怎么办呢?这下就需要我们的斜率优化对于$O(N^2)$的时间复杂度降维。
首先,我们对这个式子化简:
我们考虑两个决策点$k$与$j$,如果决策$j$更优,那么也就是
$$dp[j]+M+(sum[i]-sum[j])^2 消去共同项,得: $$dp[j]+sum[j]^2-2×sum[i]×sum[j] 即$$dp[j]+sum[j]^2-(dp[k]+sum[k]^2)<2×sum[i]×(sum[j]-sum[k])$$ 若$j>k$,则$$sum[j]-sum[k]>0$$ 可得$${\frac{{dp\text{[}j\text{]}+sum\text{[}j\mathop{{\text{]}}}\nolimits^{{2}}-\text{(}dp\text{[}k\text{]}+sum\text{[}k\mathop{{\text{]}}}\nolimits^{{2}}\text{)}}}{{2 \times \text{(}sum\text{[}j\text{]}-sum\text{[}k\text{]}\text{)}}}} 反之,若$j 则可得$$ 我们把$dp[j]+sum[j]^2$看做是$y_j$,把$2×sum[j]$看成是$x_j$。 左边$\frac{y_j-y_k}{x_j-x_k}$似乎是斜率的表示? 若$j>k$,则$\frac{y_j-y_k}{x_j-x_k} 若$j 更强的性质: 若有三个决策点,满足$k 但是这是为什么呢? 分三种情况讨论: 设当前点为$a$ 不论如何,$j$都无法成为最佳决策点,所以可以排除$j$。 于是,所有的决策点满足一个下凸包性质。 接下来看看如何找最优解。 设$k 由于我们排除了$g[i,j] 这样,从左到右,斜率之间就是单调递增的了。当我们的最优解取得在$j$点的时候,那么$k$点不可能再取得比$j$点更优的解了,于是$k$点也可以排除。 换句话说,$j$点之前的点全部不可能再比$j$点更优了,可全部从解集中排除。这是为什么呢?因为$sum[i]$随着$i$的增长也是单调递增的。 所以,对于两个决策点$j$和$k$,设$j 设有三个点$i,j,k$。其中$x_i>x_j>x_k$。如何判断三点是上凸还是下凸? 用向量的叉积运算即可。 向量可以看做是二维平面坐标中的有向线段。向量的起点可以自由选择,即可以把它在平面内任意平移。平移过后的向量与原平移前完全等价。 如果一条有向线段的起点为$(x_1,y_1)$,终点为$(x_2,y_2)$。我们可以将它平移,使得起点位置为$(0,0)$,终点位置为$(x_2-x_1,y_2-y_1)$。 此时向量的大小和方向不变。我们以后谈及向量,都默认它的起点在$(0,0)$处,而只以它的终点表示该向量。 设有向量$p_1(x_1,y_1)$,$p_2(x_2,y_2)$。他们的叉乘为$p_1×p_2=(x_1*y_2-x_2*y_1)$。 叉乘的物理意义为以向量$p_1$和$p_2$为相邻两边的平行四边形的有向面积。 平面四边形在两向量的顺时针方向,则为正,反之则为负。如何判断$p_1$与$p_2$的位置关系? 所以我们可以令向量$p_1=(x_j-x_k,y_j-y_k),p_2=(x_i-x_j,y_j-y_k)$,再用叉积即可判断$i,j,k$是上凸还是下凸。 练习题: $HDU2829,HDU3480,POJ3709$
{\frac{{dp\text{[}j\text{]}+sum\text{[}j\mathop{{\text{]}}}\nolimits^{{2}}-\text{(}dp\text{[}k\text{]}+sum\text{[}k\mathop{{\text{]}}}\nolimits^{{2}}\text{)}}}{{\left. 2*\text{(}sum\text{[}j\text{]}-sum\text{[}k\text{]} \right) }}}>sum[i]$$
感性理解就是:如果两个决策点的斜率小于$sum[i]$,则靠后的决策点更优;否则靠前的决策点更优。
另外注意:比较斜率避免用除法。
下见代码#include