原题链接:https://www.lydsy.com/JudgeOnline/problem.php?id=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
题解
大家知道我要说什么。。。
太水了,直接上公式,用 dp[i] d p [ i ] 表示在第 i i 个检查点设哨塔时对于前个点的最优花费.
设
j<i
j
<
i
易得:
显然,需要斜率优化,设
k<j<i
k
<
j
<
i
且
k
k
优于:
dp[k]+i2−2ik−i+k2+k2<dp[j]+i2−2ij−i+j2+j2 d p [ k ] + i 2 − 2 i k − i + k 2 + k 2 < d p [ j ] + i 2 − 2 i j − i + j 2 + j 2
dp[k]−dp[j]+k2+k−j2−j2<ik−ij d p [ k ] − d p [ j ] + k 2 + k − j 2 − j 2 < i k − i j
dp[k]−dp[j]+k2+k−j2−j2k−j>i d p [ k ] − d p [ j ] + k 2 + k − j 2 − j 2 k − j > i
i i 单增。。。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=1e6+5;
ll n,que[M];
ll a[M],dp[M],sum[M];
void in()
{
scanf("%lld",&n);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
}
double slop(ll k,ll j)
{
return 1.0*(dp[k]-dp[j]+(k*k+k-j*j-j)/2)/(k-j);
}
void ac()
{
ll k,le=0,ri=0;
for(int i=1;i<=n;++i)
{
while(le<ri&&slop(que[le],que[le+1])<i)le++;
k=que[le];
dp[i]=dp[k]+a[i]+(i-k)*(i-k-1)/2;
while(le<ri&&slop(que[ri],i)<slop(que[ri-1],que[ri]))ri--;
que[++ri]=i;
}
printf("%lld",dp[n]);
}
int main()
{
in();ac();
return 0;
}