bzoj 3156: 防御准备

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


把a[i]反过来。

f[i]表示在第i个点修防御塔的最小值

f[i]=min(f[j]+(i-j)*(i-j-1)/2)+a[i]

推一下方程

2*(f[j]-f[k])<(i-k)*(i-k-1)-(i-j)(i-j-1)

(2*(f[j]-f[k])+j(j+1)-k(k+1)/2*(j-k)<i

维护一个凸包。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#define ll long long
const int N=1100000;
ll f[N];
ll sa[N],sb[N];
int yu[N];
int n;
double slope(int k,int j)
{
return ((double)2*(double)(f[j]-f[k])+(double)j*(double)(j+1)-(double)k*(double)(k+1))/double((double)2*(double)(j-k)); 
}
ll min(ll x,ll y)
{
if(x<y) return x;
return y;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&sa[i]);
int len=0;
for(int i=n;i>=1;i--)
sb[++len]=sa[i];
ll ans=sb[1]+(ll)n*(ll)(n-1)/(ll)2; 
int l=1,r=1;yu[1]=1;
f[1]=sb[1];
for(int i=2;i<=n;i++)
{
while(l<r&&slope(yu[l],yu[l+1])<(double)i) l++;
int k2=yu[l];
f[i]=f[k2]+(ll)(i-k2)*(ll)(i-k2-1)/2+sb[i];
ans=min(ans,f[i]+(ll)(n-i)*(ll)(n+1-i)/(ll)2);
while(l<r&&slope(yu[r-1],yu[r])>slope(yu[r],i)) r--;
yu[++r]=i;
}
printf("%lld\n",ans);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值