[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
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; }