1. 程式人生 > >讓菜雞講一講斜率優化

讓菜雞講一講斜率優化

body problem pla 就是 lock 並且 gpo str int

終於把坑填到了這兒


眾所周知,斜率優化一般可以用在DP

而你可以發現斜率優化其實就是單調隊列優化的進化


我們在做DP題的時候,有時會遇到這種轉移方程

\[f(i)=min(f(j)+a(i)b(j))+C\]

C是個可能和i有關的常數,在下面我們方便敘述把它忽略掉

而a,b只和i,j有關,並且它們都單調(取min的時候,是a單減b單增的)

我們先設這個f(i)的最優值由j轉移過來

而另一個位置k是一個可以轉移但不是最優的奇怪位置

所以可以得到\(f(j)+a(i)b(j)<f(k)+a(i)b(k)\)

所以可以得到\(a(i)(b(j)-b(k))<f(k)-f(j)\)

所以可以得到\(a(i)<\frac{f(k)-f(j)}{b(j)-b(k)}\)

我們先設\(slp(j,k)=\frac{f(k)-f(j)}{b(j)-b(k)}\)slp=slope

那麽我們搞一個單調隊列維護它們

假設現在我們要算出f(i)

那麽關於彈隊首,如果\(slp(q[he],q[he+1])\leq a(i)\),就把q[he]彈掉。

因為這個式子滿足的時候,就說明q[he]不如q[he+1]優。

彈隊尾的話,如果\(slp(q[ta-1],q[ta])\geq slp(q[ta],i)\),就把q[ta]彈掉。

因為這個式子滿足的時候,就說明q[ta-1]不會比q[ta]優。

其實如果滿足的話,就意味著如果之後從隊首彈q[ta-1]的時候必須也要彈掉q[ta],所以這個q[ta]卵用沒有

那麽這兒有個模板題

和對應的代碼

(因a,b函數的不同可能會引起符號差異)

#include<bits/stdc++.h>
using namespace std;
typedef long long lint;
inline int gotcha()
{
    register int a=0,b=1,c=getchar();
    while(!isdigit(c))b^=c=='-',c=getchar();
    while(isdigit(c))a=a*10
+c-48,c=getchar(); return b?a:-a; } const int _ = 50002; int n,L; lint f[_],co[_],sc[_]; #define twi(a) ((a)*(a)) lint A(int i){return sc[i]+i-1-L;} lint B(int i){return sc[i]+i;} double slope(int j,int k) {return 1.00*(f[j]+twi(B(j))-f[k]-twi(B(k)))/(2*(B(j)-B(k)));} int q[_],he,ta; int main() { register int i,j; memset(f,63,sizeof(f)),f[0]=sc[0]=0; n=gotcha(),L=gotcha(); for(i=1;i<=n;i++)co[i]=gotcha(),sc[i]+=sc[i-1]+co[i]; for(i=1,he=ta=0;i<=n;i++) { while(he<ta && slope(q[he],q[he+1])<=A(i))he++; j=q[he],f[i]=f[j]+twi(A(i)-B(j)); while(he<ta && slope(q[ta-1],q[ta])>=slope(q[ta],i))ta--; q[++ta]=i; } printf("%lld",f[n]); return 0; }

讓菜雞講一講斜率優化