三练斜率优化

[bzoj3156]防御准备

试题描述

背景

  在美丽富饶的Katharon国中生活着一群快乐的小木偶。他们衣食无忧,自给自足。然而在某一天,来自外形的X过要对Katharon国,发起攻击,国家安危迫在眉睫,下面请你来做战前的防御准备工作。

描述

  我们定义战线为一条长度为n的序列,在这条战线上共设有n个检查点,从左到右依次标号为1到n。一个战线为合法战线当且仅当任意一个检查点可以通过安全检查。对于第i个检查点可以通过安全检查的方式有两种,第一种是放置一个守卫塔,这将花费ai的费用。第二种方式是放置一个木偶,放置木偶的话费等于这个检查点右侧第一个守卫塔到它的距离。举例来说,若检查点第i个位置放置一个木偶,检查点右侧第一个守卫塔位置为j(i < j),则在点i放置木偶的花费为j - i.当然,第n个检查点只能放置守卫塔,因为它的右面不可能再存在别的守卫塔了。我们定义战线花费为所有守卫塔的花费加上所有木偶的花费,现在Katharon国的国王hzc君将提供给你每个位置放置守卫塔的费用以及战线的总长度,请你求出最小的战线花费值。

输入

第一行为一个整数N表示战线的总长度。

第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai。

输出

共一个整数,表示最小的战线花费值。

输入示例

10
2 3 1 5 4 5 6 3 1 2

输出示例

18

数据范围

1<=N<=10^6,1<=Ai<=10^9

题解

原题试题描述是一张截图。我没事闲的,也为方便你们查题解,手打了一份。。。

不用多说,此题和[bzoj3437]小P的牧场极其相似,但是简单多了,不需要“反着”考虑。

设f(i)表示使前i个检查点合法,并且第i个点放置守卫塔的最小花费。

转移和斜率优化做法留给读者思考。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <cstdlib>
using namespace std;

const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *tail;
inline char Getchar() {
    if(Head == tail) {
        int l = fread(buffer, 1, BufferSize, stdin);
        tail = (Head = buffer) + l;
    }
    return *Head++;
}
int read() {
    int x = 0, f = 1; char c = Getchar();
    while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
    while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
    return x * f;
}

#define maxn 1000010
#define LL long long
int n, A[maxn], l, r, q[maxn];
LL f[maxn];

double slop(int j, int k) {
    return (double)((f[j] << 1ll) - (f[k] << 1ll) + (double)j * j + j - (double)k * k - k) / (2.0 * (j - k));
}

int main() {
    n = read();
    for(int i = 1; i <= n; i++) A[i] = read();
    
    l = r = 1; q[r] = 0;
    for(int i = 1; i <= n; i++) {
        while(l < r && slop(q[l], q[l+1]) < i) l++;
        f[i] = f[q[l]] + ((LL)(i - q[l]) * (LL)(i - q[l] - 1) >> 1ll) + A[i];
        // for(int t = l; t <= r; t++) printf("%d(%lld) ", q[t], f[q[t]]); putchar('
');
        while(l < r && slop(q[r], i) < slop(q[r-1], q[r])) r--;
        q[++r] = i;
    }
    
    printf("%lld
", f[n]);
    
    return 0;
}
代码?点这儿!
原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/5152118.html