bzoj3156 防御准备

题意

传送门

题解

设 $f[i]$ 表示在第 $i$ 个点建一个塔,$1$ 到 $i$ 都完成的最小代价。

我们可以得到:

$$f[i]=\min_{j=1}^{i-1}\left(f[j]+a_i+\sum_{k=j+1}^{i-1}\left(i-k\right)\right)$$

由于 $i-i=0$,所以我们变形

$$f[i]=\min_{j=1}^{i-1}\left(f[j]+a_i+\sum_{k=j+1}^{i}\left(i-k\right)\right)$$

然后我们展开,假设 $f[i]$ 在 $j$ 点取得最小值,$sum[i]$ 表示 $1+\cdots+i$,

$$f[i]=f[j]+a_i+(i-j)i-sum[i-1]+sum[j]$$

我们展开,移项,得

$$f[j]+sum[j]=f[i]+sum[i-1]-a_i-(i-j)i$$

在 $sum[i-1]$ 中加上一个 $i$ 然后再减,得到

$$f[j]+sum[j]=f[i]+sum[i]-i-a_i-i^2-ij$$

然后就可以用斜率优化了。$h(i)=f[i]+sum[i]$。

调试记录

  • 没开 long long
  • 前缀和错误

代码

#include <bits/stdc++.h>
using namespace std;

#define int long long
int n;
int a[1000005], f[1000005], sum[1000005], q[1000005];

inline int h(int i) {
    return f[i] + sum[i];
}

signed main() {
    scanf("%lld", &n);
    sum[0] = 0;
    for (int i=1; i<=n; i++)  {
        scanf("%lld", &a[i]);
        sum[i] = sum[i-1] + i;
    }
    f[0] = 0;
    int l = 0, r = 0;
    for (int i=1; i<=n; i++) {
        while (l < r  && h(q[l+1]) - h(q[l]) < (q[l+1] - q[l]) * i) ++l;
        f[i] = h(q[l]) - q[l] * i + i * i + a[i] - sum[i];
        while (l < r && (h(i) - h(q[r])) * (q[r] - q[r-1]) < (i - q[r]) * (h(q[r]) - h(q[r-1]))) --r;
        q[++r] = i;
    }
    printf("%lld\n", f[n]);
    return 0;
}

 

posted @ 2018-08-12 19:12  MCH__ds  阅读(173)  评论(0编辑  收藏  举报