题目
题解
斜率优化DP
设f[i]表示前i个士兵最大战斗力之和,有
去掉max,把仅与j有关的移到一边,另一边放与仅与i有关的或和i、j都有关的,得
根据上式,斜率为,决策点坐标为,截距为。
因为要求截距最大,所以我们要维护一个上凸壳,即斜率递减。这点用来维护队尾。
考虑问题斜率,是递减的,所以一个小于当前问题斜率的斜率是不优秀的,根据这一点可以删除队头。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int n;
ll a,b,c;
int x[maxn];ll sx[maxn];
ll f[maxn];
int q[maxn];int l,r;
double calc(int j1,int j2)
{
return (double)((f[j1] + a*sx[j1]*sx[j1] - b*sx[j1]) - (f[j2] + a*sx[j2]*sx[j2] - b*sx[j2])) / (sx[j1] - sx[j2]);
}
int main()
{
scanf("%d",&n);
scanf("%lld%lld%lld",&a,&b,&c);
for(int i=1;i<=n;i++) scanf("%d",&x[i]),sx[i]=sx[i-1]+x[i];
f[0]=0;
q[l=r=0]=0;
for(int i=1;i<=n;i++)
{
while(l<r && calc(q[l],q[l+1])>=2*a*sx[i]) l++;
int j=q[l];
f[i]=f[j] + a*sx[i]*sx[i] -2*a*sx[i]*sx[j] + a*sx[j]*sx[j] + b*sx[i] - b*sx[j] + c;
while(l<r && calc(q[r-1],q[r])<=calc(q[r],i)) r--;//维护斜率递减
q[++r]=i;
}
printf("%lld\n",f[n]);
return 0;
}