zoukankan      html  css  js  c++  java
  • 三练斜率优化

    [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;
    }
    代码?点这儿!
  • 相关阅读:
    【分区】使用 MBR 分区表分区并格式化
    微信小程序公司开发前必读
    Delphi 经典书籍
    sybase 通过select into创建新表
    sybase 创建触发器
    delphi 判断exe重复执行
    git 的诞生
    git 常用命令
    mvn spring-boot:run运行不了的解决办法
    git 提交代码
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/5152118.html
Copyright © 2011-2022 走看看