这道题一看就是dp,不过数据范围让我们不能O(n^2),所以就要优化。dp方程为f[i]=min(f[j]+(i-j)*(i-j-1)/2+a[i]),这种形式便想到了斜率优化。
设i>j>k,j比k优
f[j]+(i-j)* (i-j-1)/2+a[i]< f[k]+(i-k)* (i-k-1)/2+a[i]
化得
[(f[j]+j* (j+1)/2)-(f[k]+k* (k+1)/2)]/(j-k)< i
设Y[i]=f[i]+i*(i+1)/2,X[i]=i
(Y[j]-Y[k])/(X[j]-X[k])< i
化为斜率形式后,就可以做了。(大坑点:全部要long long)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
long long f[1100000],a[1100000],v[11000000];
long long YY(long long x){return f[x]+x*(x+1)/2;}
long long Y(long long x,long long y){return YY(y)-YY(x);}
long long X(long long x,long long y){return y-x;}
int main()
{
long long n;
scanf("%lld",&n);
for(long long i=1;i<=n;i++)scanf("%lld",&a[i]);
long long head=1,tail=1;
for(long long i=1;i<=n;i++)
{
while(head<tail && Y(v[head],v[head+1])<i*X(v[head],v[head+1]))head++;
long long x=v[head];
f[i]=f[x]+(i-x)*(i-x-1)/2+a[i];
while(head<tail && Y(v[tail-1],v[tail])*X(v[tail],i)>Y(v[tail],i)*X(v[tail-1],v[tail]))tail--;
v[++tail]=i;
}
printf("%lld\n",f[n]);
return 0;
}