讓菜雞講一講斜率優化

終於把坑填到了這兒c++


衆所周知,斜率優化通常能夠用在DPgit

而你能夠發現斜率優化其實就是單調隊列優化的進化函數


咱們在作DP題的時候,有時會遇到這種轉移方程優化

$$f(i)=min(f(j)+a(i)b(j))+C$$spa

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

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

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

而另外一個位置k是一個能夠轉移但不是最優的奇怪位置it

因此能夠獲得$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;
}
相關文章
相關標籤/搜索