Solution
设
f[x]
表示特别行动队前
x
名士兵编好队的最大战斗力。
化简、移项:得到斜率方程:
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;
}