浅谈斜率优化

斜率优化

如果对于方程形如这样的

我们不能对其进行比较有效果的优化,因为它的转移,涉及到了关于i和关于j的一些数组,这时我们就需要用斜率优化了。

通常我们令k<j<i,且用j来更新F[i]比用j优。则有

并且我们都可以化成如下形式,X[j],Y[j]指只关于j的数,X[k],Y[k]亦之

我们可以根据这个式子,来优化DP。这大概就是斜率优化的主要思想

实践出真知,让我们看一下HDU3507

很容易可以推出状态转移方程

令k<j<i,那么就可以得到

 

移项可得

如果我们令Y[i]=F[i]+A[i]²,X[i]=A[i],那么可以转化成如上形式

优化DP

根据刚才的推算,可以发现,要是满足这个条件的转移,选j一定比k要优。

我们抽象的把X[i],Y[i]想象成平面上的点,那么这个式子所表示的含义就是两个点所连成的这条线的斜率。

但是这个斜率又是怎么样的呢?

我们令g(i,j)表示i点和j点的斜率(上面式子的左边,k<j<i)。假设g(i,j)<g(j,k)。①如果g(i,j)<F[i](这个F[i]斜率式子右边的F[i])那么i一定比j优,则j不必选。②如果g(i,j)>F[i],那么j比i优,但是k又比j优,还是不选j。

总结出来,如果g(i,j)<g(j,k),那么j就是废物,可以T掉。

我们发现,这种情况就是

那么最后剩下的图形,就是一个下凸包壳,也就是斜率单调

优化实现

我们就例题而言

维护一个单调队列p.get为斜率

表示存的可能为答案的点。因为我们要维护下凸包的性质,必须满足get(p[tail-1],p[tail])>get(p[tail],i)

我们根据斜率式子,队首必须满足get(p[head],p[head+1])<2A[i]

因为斜率越小越优,所以每次选队首。

大致可以有如下代码:

while (head<tail) and (get(p[tail-1],p[tail])>get(p[tail],i)) do dec(tail);

加入新增可供转移的节点

while (head<tail) and (get(p[head],p[head+1])<...) do inc(HeaD)

动态规划转移

练习题

bzoj1010[HNOI2008]玩具装箱 

bzoj1096[ZJOI2007]仓库建设

bzoj1597[USACP2008 Mar]土地购买 

bzoj1911[Apio2010]特别行动队 

bzoj3156 防御准备 

bzoj3675[Apio2014] 序列分割 

bzoj3437 小P的牧场 

bzoj4518[SDOI2016] 征途 

原文地址:https://www.cnblogs.com/philchieh/p/8044577.html