bzoj3156 防御准备

Posted mchmch

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 ight) ight)$$

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

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

然后我们展开,假设 $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
", f[n]);
    return 0;
}

 

以上是关于bzoj3156 防御准备的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3156 防御准备

bzoj 3156: 防御准备

BZOJ3156防御准备 斜率优化

bzoj3156防御准备 斜率优化dp

BZOJ - 3156: 防御准备

BZOJ 3156 防御准备