3156: 防御准备
Description
Input
第一行为一个整数N表示战线的总长度。
第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai。
Output
共一个整数,表示最小的战线花费值。
Sample Input
10
2 3 1 5 4 5 6 3 1 2
dp[i]=dp[j]+a[i]+(i-j)*(i-j-1)/2;
如果j比k优
dp[j]+(i-j)(i-j-1)/2 < dp[k]+(i-k)*(i-k-1)/2;
dp[j]-dp[k]+(j*j+j)/2 - (k*k+k)/2 < i*(j-k);
注意要用long long
#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N = 1000000 + 5;
ll f[N],cost[N],q[N];
int n,head=1,tail=1;
double xie( ll j, ll k ){ return (2.0*(f[j]-f[k])+j*(j+1)-k*(k+1))/(2.0*j-2.0*k);}
int main(){
scanf("%d", &n);
for( int i = 1; i <= n; i++ ) scanf("%lld", &cost[i]);
for( int i = 1; i <= n/2; i++ ) swap( cost[i], cost[n-i+1] );
f[1] = cost[1]; ll ans = cost[1] + 1ll*n*(n-1)/2ll; q[1] = 1;
for( int i = 2; i <= n; i++ ) {
while( head < tail && xie( q[head+1], q[head] ) < i ) head++;
f[i] = f[q[head]] + 1ll*(i-q[head])*(i-q[head]-1)/2 + cost[i];
ans = min( ans, f[i] + 1ll*(n-i+1)*(n-i)/2 );
while( head < tail && xie( q[tail], q[tail-1] ) > xie( i, q[tail] )) tail--;
q[++tail] = i;
}
printf("%lld", ans);
return 0;
}