终于把坑填到了这儿c++
众所周知,斜率优化通常能够用在DP上git
而你能够发现斜率优化其实就是单调队列优化的进化函数
咱们在作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; }