洛谷P3628 [APIO2010]特別行動隊(動態規劃,斜率優化,單調隊列)

洛谷題目傳送門html

安利蒟蒻斜率優化總結優化

因爲人是每次都是連續一段一段地選,因此考慮直接對\(x\)記前綴和,設如今的\(x_i=\)原來的\(\sum\limits_{j=1}^ix_i\)spa

\(f_i\)爲安排前\(i\)我的的最大值\((f_0=0)\)code

\(f_i=\max\limits_{j=0}^{i-1}\{f_j+a(x_i-x_j)^2+b(x_i-x_j)+c\}\)
\(\quad=\max\limits_{j=0}^{i-1}\{f_j-2ax_ix_j+ax_j^2-bx_j\}+ax_i^2+bx_i+c\)htm

決策\(j\)\(k\)優當且僅當blog

\[f_j-2ax_ix_j+ax_j^2-bx_j\ge f_k-2ax_ix_k+ax_k^2-bx_k\]隊列

\[\frac{f_j+ax_j^2-bx_j-(f_k+ax_k^2-bx_k)}{x_j-x_k}\ge 2ax_i\]get

因而每一個決策能夠當作是一個點\((x_i,y_i)(y_i=f_i+ax_i^2-bx_i)\)flash

不用考慮變號。由於\(a<0\)\(x_i\)遞增,斜率\(2ax_i\)遞減,因此咱們用單調隊列維護一個下凸包就好了。依舊是維護隊首爲當前最優解。it

固然注意這裏的轉移是從\(0\)\(i-1\),因此和土地徵用有點點不同,要先求出\(f_i\)再加入決策點\(i\)

純自然代碼

#include<cstdio>
#define RG register
#define R RG int
#define G c=getchar()
#define Calc(j,k) (y[j]-y[k])/(x[j]-x[k])//求斜率
const int N=1e6+9;
int q[N];
double f[N],k[N],x[N],y[N];//變量名同上
inline int in(){
    RG char G;RG bool f=0;
    while(c<'-')G;
    if(c=='-')f=1,G;
    R x=c&15;G;
    while(c>'-')x=x*10+(c&15),G;
    return f?-x:x;
}
int main(){
    R n=in(),i,h,t;
    RG double a=in(),b=in(),c=in(),now;
    for(i=h=t=1;i<=n;++i){
        x[i]=x[i-1]+in();//前綴和
        now=2*a*x[i];//當前斜率
        while(h<t&&k[h]>=now)++h;
        f[i]=-now*x[q[h]]+y[q[h]]+(a*x[i]+b)*x[i]+c;//先求fi,根據定義式求
        y[i]=f[i]+(a*x[i]-b)*x[i];//yi跟着求
        while(h<t&&k[t-1]<=Calc(q[t],i))--t;//維護凸包
        k[t]=Calc(q[t],i);q[++t]=i;
    }
    printf("%.0lf\n",f[n]);
    return 0;
}
相關文章
相關標籤/搜索