https://loj.ac/problem/10190
题目描述
有(n)个士兵,每个士兵有一定的战斗力,分为若干支特别行动队,每支行动队内的士兵编号连续,令(x=sum x_i),那么这支特别行动队的战斗力为(ax^2+bx+c),求最大战斗力。
思路
考虑用(f[i])表示前(i)个人能到达的战斗力,那么方程比较简单,就是把(k+1sim j)分为一组
[f[i]=min{f[j]+a(sum[i]-sum[j])^2+b(sum[i]-sum[j])+c}
]
我们尝试把这个式子化为与(j)相关的一次函数
[f[j]+a*sum[j]^2=(2*a*sum[i]+b)*sum[j]-a*sum[i]^2-b*sum[i]-c
]
对于这个式子我们显然可以用斜率优化优化为(O(N))
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e6+10;
ll read()
{
ll res=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
return res*w;
}
ll a,b,c,sum[N],f[N],q[N];
ll Y(ll x){return f[x]+a*sum[x]*sum[x];}
ll K(ll x){return 2*a*sum[x]+b;}
ll X(ll x){return sum[x];}
int main()
{
ll n=read();
a=read(),b=read(),c=read();
for(ll i=1;i<=n;i++)
sum[i]=sum[i-1]+read();
ll l=0,r=0;
for(ll i=1;i<=n;i++)
{
while(l<r&&(Y(q[l+1])-Y(q[l]))>=K(i)*(X(q[l+1])-X(q[l])))l++;
ll x=sum[i]-sum[q[l]];
f[i]=f[q[l]]+a*x*x+b*x+c;
while(l<r&&(Y(q[r])-Y(q[r-1]))*(X(i)-X(q[r]))<=(Y(i)-Y(q[r]))*(X(q[r])-X(q[r-1])))r--;
q[++r]=i;
}
printf("%lld",f[n]);
}