又是一道非常标准的斜率优化。
一开始还以为需要讨论a来判断是维护上凸包还是下凸包,233。又看了眼数据范围,a一定小于0,嗯,这就轻松多了。
for(int i=1;i<=n;i++)A[i]=read();
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+A[i];
for(int i=1;i<=n;i++)
for(int j=0;j<i;j++)
f[i]=max(f[i],f[j]+func(sum[i]-sum[j]));
cout<<f[n];
n^2转移,再推一推公式,
斜率为
(double)(f[i]-f[j]+b*(sum[j]-sum[i])+a*(sum[i]sum[i]-sum[j]*sum[j]))/(double)(2*a(sum[i]-sum[j])),好长啊
#include<bits/stdc++.h>
#define LL long long
#define N 1000000
using namespace std;
LL n,a,b,c;
LL A[N+1],sum[N+1];
LL f[N+1],l,r,q[N+1];
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline LL read()
{
LL x=0,f=1;
char c=nc();
while((c<'0'||c>'9')&&c!='-')c=nc();
if(c=='-')f=-1,c=nc();
while(c<='9'&&c>='0')x=x*10+c-'0',c=nc();
return x*f;
}
LL func(LL x)
{
return a*x*x+b*x+c;
}
double slope(int i,int j)
{
return (double)(f[i]-f[j]+b*(sum[j]-sum[i])+a*(sum[i]*sum[i]-sum[j]*sum[j]))/(double)(2*a*(sum[i]-sum[j]));
}
int main()
{
n=read();
a=read(),b=read(),c=read();
for(int i=1;i<=n;i++)A[i]=read();
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+A[i];
// for(int i=1;i<=n;i++)
// for(int j=0;j<i;j++)
// f[i]=max(f[i],f[j]+func(sum[i]-sum[j]));
// cout<<f[n];
l=1,r=0,q[++r]=0;
for(int i=1;i<=n;i++)
{
while(l<r&&slope(q[l+1],q[l])<=sum[i])l++;
int tmp=q[l];
f[i]=f[tmp]+a*(sum[i]-sum[tmp])*(sum[i]-sum[tmp])+b*(sum[i]-sum[tmp])+c;
while(l<r&&slope(i,q[r])<slope(q[r],q[r-1]))r--;
q[++r]=i;
}
cout<<f[n];
return 0;
}
貌似还有一种斜率不是单调的,十分毒瘤,要用CDQ分治之类的,我还是不会233