防御准备

防御准备

给定一个长为n的序列,每个点需要放置一个守卫塔或一个木偶。

在第i个点放置守卫塔的代价为a_i,放置木偶的代价为j-i,j为i右边第一个守卫塔;求最小代价。

1≤n≤10^6,1≤a_i≤10^9

推出朴素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\n", f[n]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/MyNameIsPc/p/9463994.html