特别行动队

题目传送门

其实这题直接推式子,不需要转换,还是很简单的。
考虑用 \(f_i\) 表示前 \(i\) 名士兵修正战斗力之和的最大值。令 \(X=sum_i-sum_j\),易得 \(f_i=f_j+aX^2+bX+c\)

\(X=sum_i-sum_j\) 代入得 \(f_i=f_j+a(sum_i-sum_j)^2+b(sum_i-sum_j)+c\)。其中 \(i\) 是常量。展开得 \(f_i=f_j+asum_i^2+asum_j^2-2asum_isum_j+bsum_i-bsum_j+c\)

\[(f_j+asum_j^2-bsum_j)=(2asum_i)sum_j+(f_i-asum_i^2-bsum_i-c) \]

\[y=kx+b \]

\(\max b\)

\(k\) 递减,\(x\) 递增

维护一个上凸包即可。

#include<bits/stdc++.h>
using namespace std;
#define L(i,l,r) for(int i=l;i<=r;++i)
#define R(i,l,r) for(int i=r;i>=l;--i)
const int N=1000010;
int n,sum[N],q[N];
typedef long long ll;
ll f[N],a,b,c;
#define y(j) (f[j]+a*sum[j]*sum[j]-b*sum[j])
namespace IO{
    int len=0;
    char ibuf[(1<<20)+1],*iS,*iT,out[(1<<25)+1],ar[50];
    #define gh()\
    (iS==iT?iT=(iS=ibuf)+fread(ibuf,1,(1<<20)+1,stdin),\
    (iS==iT?EOF:*iS++):*iS++)
    void read(){}
    template<typename Type,typename...Types>
    void read(Type&x,Types&...xs){
        char ch=gh();
        char t=0;
        while(ch<'0'||ch>'9')t|=ch=='-',ch=gh();
        while(ch>='0'&&ch<='9')x=x*10+(ch^48),ch=gh();
        x=t?-x:x;
        read(xs...);
    }
    void putc(char ch){out[len++]=ch;}
    void write(char c){}
    template<typename Type, typename... Types>
    void write(char c,Type&x,Types&...xs){
        int tot=0;
        if(!x)putc('0');
        if(x<0)putc('-'),x=-x;
        while(x)ar[++tot]=x%10+'0',x/=10;
        for(int i=tot;i;--i)putc(ar[i]);
        putc(c);
        write(c,xs...);
    }
    void flush(){
        fwrite(out,1,len,stdout);
        len=0;
    }
}
using namespace IO;
int main(){
    // freopen("1.in","r",stdin);
    // freopen("1.out","w",stdout);
    // ios::sync_with_stdio(0);
    // cin.tie(0);
    // cout.tie(0);
    read(n,a,b,c);
    L(i, 1, n){
        read(sum[i]);
        sum[i]+=sum[i-1];
    }
    int hh=0,tt=0;
    L(i, 1, n){
        while(hh<tt&&(y(q[hh+1])-y(q[hh]))>=2*a*sum[i]*(sum[q[hh+1]]-sum[q[hh]]))++hh;
        int j=q[hh],X=sum[i]-sum[j];
        f[i]=f[j]+a*X*X+b*X+c;
        while(hh<tt&&(y(q[tt])-y(q[tt-1]))*(sum[i]-sum[q[tt]])<=(y(i)-y(q[tt]))*(sum[q[tt]]-sum[q[tt-1]]))--tt;
        q[++tt]=i;
    }
    printf("%lld",f[n]);
    return 0;
}
posted @ 2023-04-29 08:01  wscqwq  阅读(8)  评论(0编辑  收藏  举报