[BZOJ1705] [Usaco2007 Nov]Telephone Wire 架设电话线

Description

最近,Farmer John的奶牛们越来越不满于牛棚里一塌糊涂的电话服务 于是,她们要求FJ把那些老旧的电话线换成性能更好的新电话线。 新的电话线架设在已有的N(2 <= N <= 100,000)根电话线杆上, 第i根电话线杆的高度为height_i米(1 <= height_i <= 100)。 电话线总是从一根电话线杆的顶端被引到相邻的那根的顶端 如果这两根电话线杆的高度不同,那么FJ就必须为此支付 C*电话线杆高度差(1 <= C <= 100)的费用。当然,你不能移动电话线杆, 只能按原有的顺序在相邻杆间架设电话线。Farmer John认为 加高某些电话线杆能减少架设电话线的总花费,尽管这项工作也需要支出一定的费用。 更准确地,如果他把一根电话线杆加高X米的话,他得为此付出X^2的费用。 请你帮Farmer John计算一下,如果合理地进行这两种工作,他最少要在这个电话线改造工程上花多少钱。

Input

* 第1行: 2个用空格隔开的整数:N和C

* 第2..N+1行: 第i+1行仅有一个整数:height_i

Output

* 第1行: 输出Farmer John完成电话线改造工程所需要的最小花费

Sample Input

5 2
2
3
5
1
4
输入说明:
一共有5根电话线杆,在杆间拉电话线的费用是每米高度差$2。
在改造之前,电话线杆的高度依次为2,3,5,1,4米。


Sample Output

15
输出说明:
最好的改造方法是:Farmer John把第一根电话线杆加高1米,把第四根加高2米,
使得它们的高度依次为3,3,5,3,4米。这样花在加高电线杆上的钱是$5。
此时,拉电话线的费用为$2*(0+2+2+1) = $10,总花费为$15。

 


 

 

设$f[i][j]$为前$i$个树,第$i$个高度是$j$的最小花费。

显然$f[i][j] = min(f[i - 1][k] + (j - h[i])^2 +C \times (k - j))$。

这样是$O(N \times h^2)$的不太可过。

我们拆开发现

$f[i][j] = f[i-i][k]+C \times j - C \times k,k \leq j$

$f[i][j] = f[i-1][k]-C \times j + C \times k, k > j$.

发现其实就是维护$f[i-1][k]-C \times k$的前缀最小值和$f[i-1][k]+c \times k$的后缀最大值。

于是就可以$O(N \times h)$做出。

 

 


 

 

 

#include <iostream>
#include <cstdio> 
#include <algorithm>
#include <cstring>
#include <queue>
#include <cmath>
using namespace std;
#define reg register
#define gc getchar
inline int read() {
    int res=0;char ch=gc();bool fu=0;
    while(!isdigit(ch))fu|=(ch=='-'), ch=gc();
    while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48), ch=gc();
    return fu?-res:res;
}
#define N 100005
#define ll long long
int n, C;
int h[N];
ll f[N][105];
ll ans = 1e16;
ll mnt[105], mnw[105];

int main()
{
    n = read(), C = read();
    for (reg int i = 1 ; i <= n ; i ++) h[i] = read();
    for (reg int i = 1 ; i <= n ; i ++)
        for (reg int j = 1 ; j <= 100 ; j ++)
            f[i][j] = 1e16;
    for (reg int i = h[1] ; i <= 100 ; i ++) f[1][i] = (h[1] - i) * (h[1] - i);
    
    for (reg int i = 2 ; i <= n ; i ++)
    {
        memset(mnt, 0x7f, sizeof mnt), memset(mnw, 0x7f, sizeof mnw);
        for (reg int j = 1 ; j <= 100 ; j ++) mnt[j] = min(mnt[j - 1], f[i - 1][j] - C * j);
        for (reg int j = 100 ; j >= 1 ; j --) mnw[j] = min(mnw[j + 1], f[i - 1][j] + C * j);    
        for (reg int j = h[i] ; j <= 100 ; j ++)
            f[i][j] = min(C * j + mnt[j], - C * j + mnw[j]) + (j - h[i]) * (j - h[i]);
    }
    for (reg int i = 1 ; i <= 100 ; i ++) ans = min(ans, f[n][i]);
    cout << ans << endl;
    return 0;
}

 

posted @ 2018-10-12 15:45  zZhBr  阅读(216)  评论(0编辑  收藏  举报