码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj3156 防御准备

时间:2018-08-12 21:49:11      阅读:146      评论:0      收藏:0      [点我收藏+]

标签:code   printf   pac   斜率优化   problem   php   main   fine   调试   

题意

传送门

题解

设 $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;
}

 

bzoj3156 防御准备

标签:code   printf   pac   斜率优化   problem   php   main   fine   调试   

原文地址:https://www.cnblogs.com/mchmch/p/bzoj-3156.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!