讓菜雞講一講斜率優化
阿新 • • 發佈:2018-02-05
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;
}
讓菜雞講一講斜率優化