Description
Input
第一行为一个整数N表示战线的总长度。
第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai。
Output
共一个整数,表示最小的战线花费值。
Sample Input
10
2 3 1 5 4 5 6 3 1 2
Sample Output
18
HINT
1<=N<=10^6,1<=Ai<=10^9
Source
好久没写代码了。刚好有人问这题我就稍微写下练练手。
结果写错了。翻以前的发现以前是抄标程的。。那就写篇题解好了
斜率优化
把a[i]倒置,f[i]表示最后一个防御塔在a[i]的花费
初始方程:f[i]=min(f[j]+(i-j)*(i-j-1)/2)+a[i]
设j>k且j优于k
j,k分别带入初始方程
移项得(2*(f[j]-f[k])+j*(j+1)-k*(k+1))/2(j-k)<i
维护斜率转移即可
ans=min(ans,f[i]+(n-i+1)*(n-i)/2)
#include<cstdio>
#include<algorithm>
using namespace std;
long long f[1000001];
long long a[1000001];
int q[1000001];
inline double getk(int k,int j)
{
return double((double)2*(double)(f[j]-f[k])+(double)j*(double)(j+1)-(double)k*(double)(k+1))/double((double)2*(double)(j-k));
}
int main()
{
int n;
scanf("%d",&n);
int i;
for(i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(i=1;i<=n/2;i++)
{
long long t=a[i];
a[i]=a[n+1-i];
a[n+1-i]=t;
}
long long ans=a[1]+(long long)n*(long long)(n-1)/(long long)2;
int l=1,r=1;
q[1]=1;
f[1]=a[1];
for(i=2;i<=n;i++)
{
while(getk(q[l],q[l+1])<(double)i&&l<r)
l++;
f[i]=f[q[l]]+(long long)(i-q[l])*(long long)(i-q[l]-1)/(long long)2+a[i];
ans=min(ans,f[i]+(long long)(n-i+1)*(long long)(n-i)/(long long)2);
while(getk(q[r-1],q[r])>getk(q[r],i)&&l<r)
r--;
r++;
q[r]=i;
}
printf("%lld\n",ans);
return 0;
}