f[i]表示前i个人能获得的最大战力。
f[i]=max{f[j]+w(j+1,i)|1<=j< i}.w(j+1,i)表示j+1…i组成一队获得的战斗力,把sum[i]-sum[j]代入公式即可。如果k1< k2且k1优于k2:
f[k1]-f[k2]+a*sum[k1]^2-a*sum[k2]^2+b*(sum[k2]-sum[k1])>2*a*(sum[k1]-sum[k2])*sum[i]。还是维护一个下凸曲线,保证队列中的斜率单增。
#include <cstdio>
#include <cstring>
#define ll long long
int const N=1000010;
int n,a,b,c,q[N],h=0,t=0;
ll f[N],sum[N];
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
inline double slope(int k1,int k2){//注意加括号啊。。
return (f[k1]-f[k2]+a*(sum[k1]*sum[k1]-sum[k2]*sum[k2])+b*(sum[k2]-sum[k1]))*1.0/(2.0*a*(sum[k1]-sum[k2]));
}
int main(){
// freopen("a.in","r",stdin);
n=read();a=read();b=read();c=read();
for(int i=1;i<=n;++i){int x=read();sum[i]=sum[i-1]+x;}
for(int i=1;i<=n;++i){
while(h<t&&slope(q[h],q[h+1])<(double)sum[i]) h++;
f[i]=f[q[h]]+a*((sum[i]-sum[q[h]])*(sum[i]-sum[q[h]]))+b*(sum[i]-sum[q[h]])+c;
while(h<t&&slope(q[t],i)<slope(q[t-1],q[t])) t--;
q[++t]=i;
}
printf("%lld",f[n]);
return 0;
}