斜率优化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]尽可能小,截距尽可能小,画图(本人不会)发现是个下凸包
(具体还是看大佬们的博客吧。。)
模板
不要少项!不要少项!不要少项!
f[i]的赋值可以直接用最初的式子,不用展开,推的式子写个slope就行(不要问我为啥要写这个)
标签:slope,head,队列,斜率,出队,DP,优化,单调 来源: https://www.cnblogs.com/Chencgy/p/16165926.html