防御准备
给定一个长为n的序列,每个点需要放置一个守卫塔或一个木偶。
在第i个点放置守卫塔的代价为a_i,放置木偶的代价为j-i,j为i右边第一个守卫塔;求最小代价。
1≤n≤106,1≤a_i≤109
推出朴素dp以后用斜率优化……
话说,斜率优化推出来的不等式,必须满足左边不出现i有关的项,右边出现与i相关的一条直线。因为左边要变成一堆点,右边则是条割凸包的线。
代码贼短~
#include <cstdio>
using namespace std;
typedef long long LL;
const LL maxn=1e6+5, esp=1e-6;
LL n, a[maxn], f[maxn], y[maxn], s[maxn], cur;
LL q[maxn], h, t;
inline double slope(LL p1, LL p2){
return (double)(y[p1]-y[p2])/(p1-p2); }
int main(){
scanf("%lld", &n);
for (LL i=1; i<=n; ++i) scanf("%lld", &a[i]), s[i]=s[i-1]+i;
q[t++]=0;
for (LL i=1; i<=n; ++i){
while (h<t-1&&slope(q[h], q[h+1])<i+esp) ++h; //最多删到一个点
f[i]=f[q[h]]+i*(i-q[h])-(s[i]-s[q[h]])+a[i];
y[i]=f[i]+s[i];
while (h<t-1&&slope(q[t-1], i)<slope(q[t-2], q[t-1])+esp) --t;
q[t++]=i;
}
printf("%lld
", f[n]);
return 0;
}