特别行动队
题目传送门
其实这题直接推式子,不需要转换,还是很简单的。
考虑用 \(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;
}