其他分享
首页 > 其他分享> > 斜率优化DP

斜率优化DP

作者:互联网

因为SB大佬觉得有用,于是我决定转载一下洛谷博客
%%%

优化形如\(f[i]=max/min(a[i]+b[j]+c[i]*d[j])\) \(( j < i )\)的DP方程,其中\(a[i]\) \(c[i]\)为只关于i的函数,\(b[j]\) \(d[j]\)为只关于b的函数,显然可以化成\(f[i]=max/min(b[j]+c[i]*d[j])+a[i]\) \(( j < i )\)但发现由于存在\(c[i]*d[j]\)与i j都有关的项,所以不能用朴素的单调队列继续优化(废话)

斜率优化

对决策点j,k(j<K)

考虑什么情况j一定不如k(以min为例)

j不如k即

\(b[j]+c[i]d[j]>b[k]+c[i]d[k]\)

移项

\(c[i] (d[j]-d[k])>b[k]-b[j]\)

\(c[i]>(b[k]-b[j])/(d[j]-d[k])\)(可能会变号,取决于\(d[]\)的单调性)

由于\(c[i]\)单调递增(题设),可以得到如果当前j不如k,那么以后j也不会优于k,所以可以舍弃j,想到用单调队列进行实现

定义函数\(slpoe(j,k)=(b[k]-b[j])/(d[j]-d[k])\)

显然出队条件为\(c[i]>slope(q[head],q[head+1])\)(head < tail,head tail这里是闭区间,开区间+1即可)

如何维护入队时队列单调性?

发现,对于队列中相邻三项l,m,r,两个斜率\(a=slope(l,m),b=slope(m,r)\),如果\(a>b\)因为出队条件\(c[i]>slope(q[head],q[head+1])\)那么l出队时,m必然出队\((c[i]>a>b)\) 所以单调队列的\(slope\)应该单调递增

所以x入队时

$while(head<tail \(&&\)slope(q[tail-1],q[tail])>slope(q[tail],x))$

(画画斜率可以发现维护了一个下凸包(也可能是上凸包))

这样,就可以用单调队列配上\(slope\)愉快的砍掉复杂度上一个n

关于数形结合理解,由于本人太菜,顾不做详细叙述,看看大佬们的博客吧(逃)

优化后设队头为j

\(f[j]=a[i]+b[j]+c[i]d[j]\)

\(-c[i]d[j]+f[i]=a[i]+b[j]\)

可以看做一次函数解析式,-c[i]为斜率,当d[j]=0时,即为f[i],所以直线在y轴上的截距就是所求,要取min,就让f[i]尽可能小,截距尽可能小,画图(本人不会)发现是个下凸包
(具体还是看大佬们的博客吧。。)

模板

P3628

P2120

P3195

不要少项!不要少项!不要少项!

f[i]的赋值可以直接用最初的式子,不用展开,推的式子写个slope就行(不要问我为啥要写这个)

标签:slope,head,队列,斜率,出队,DP,优化,单调
来源: https://www.cnblogs.com/Chencgy/p/16165926.html