特別行動隊

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述


Solution

f[x] 表示特別行動隊前 x 名士兵編好隊的最大戰鬥力。

f[x]=maxi1k=0fk+a[A(i)A(k)]x+b[A(i)A(k)]+c

化簡、移項:得到斜率方程:
f[k]f[j]+a[A2(k)A2(j)]b[A(k)A(j)]>2aA(i)[A(k)A(j)]

然後就可以斜率優化了。

Code

#include <iostream>
#include <cstdio>

#define LL long long
#define Min(x,y) ((x)<(y)?(x):(y))
#define Pow(x) ((x)*(x))

using namespace std;

LL n,a,b,c,Max_Right,Lastcost,INF=9223372036854777LL;

LL A[1000010],As[1000010];
LL f[1000010],fs[1000010];
double ks[1000010];

inline void in(LL &x){
    char ch=getchar();x=0;LL flag=1;
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')flag=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    x*=flag;
}

double get_y(LL x){
    return (double)f[x]/(2*a)+(double)Pow(A[x])/2-(double)b*A[x]/(2*a);
}

double get_k(LL x,LL y){
    return (double)((double)fs[x]/(2*a)+(double)Pow(As[x])/2-(double)b*As[x]/(2*a)-get_y(y))/(As[x]-A[y]);
}

int main(){

    freopen("commando.in","r",stdin);
    freopen("commando.out","w",stdout);

    in(n);
    in(a);in(b);in(c);
    for(LL i=1,tmp;i<=n;i++){
        in(tmp);
        A[i]=A[i-1]+tmp;
    }
    ks[Max_Right]=-INF;ks[Max_Right+1]=INF;
    for(LL i=1;i<=n;i++){
        for(LL j=Lastcost;j<=Max_Right;j++)
            if(A[i]>=ks[j]&&A[i]<=ks[j+1]){
                Lastcost=j;
                f[i]=fs[j]+a*Pow(A[i]-As[j])+b*(A[i]-As[j])+c;
                break;
            }
        for(LL k=Max_Right;k>=0;k--){
            double tmp=get_k(k,i);
            if(tmp>=ks[k]){
                Max_Right=k+1;
                ks[k+1]=tmp;ks[k+2]=INF;fs[k+1]=f[i];
                As[k+1]=A[i];Lastcost=Min(Lastcost,Max_Right);
                break;
            }
        }
    }
    printf("%lld\n",f[n]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章