可能是一类dp的通用优化

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$个元素,同时它的高度为$j$的最小代价。

那么总状态数是$10^5\times 10^2$,每一次转移$10^4$。正常代码不刻意卡常是无法通过的。

从数形结合看转移

写下转移方程$f[i][j]=f[i-1][k]+(j-h[i])^2+c|j-k|$发现对于同一$f[i][j]$,其每次转移是一个开口向上的二次函数,这意味着枚举前一个高度$k$时若发现代价随高度递增,那么之后状态的也不可能会更优了。

 #include<bits/stdc++.h>
#define R register int
const int maxn = ; int n,c,h[maxn],mx,ans;
int f[][],nw; inline int abs(int x){return x>?x:-x;}
int main()
{
memset(f, 0x3f3f3f3f, sizeof f);
scanf("%d%d",&n,&c);
ans = 0x3f3f3f3f;
for (R i=; i<=n; i++) scanf("%d",&h[i]), mx = h[i]<mx?mx:h[i];
for (R i=h[]; i<=mx; i++) f[][i] = (i-h[])*(i-h[]);
for (R i=; i<=n; i++)
{
for (R j=h[i]; j<=mx; j++)
{
R pre = 0x3f3f3f3f, w = (j-h[i])*(j-h[i]), val = ;
for (R k=h[i-]; k<=mx; k++)
{
val = f[nw^][k]+w+c*abs(j-k);
if (val < f[nw][j]) f[nw][j] = val;
else if (val > pre) break;
pre = val;
}
}
nw ^= ;
memset(f[nw], 0x3f3f3f3f, sizeof f[nw]);
}
for (R i=h[n]; i<=mx; i++)
ans = std::min(ans, f[nw^][i]);
printf("%d\n",ans);
return ;
}

从决策单调看转移

因为$f[i][j]=(j-h[i])^2+\{f[i-1][k]+c|j-k|\}$,而大括号内的式子与$j$无关,说明可以在枚举$j$的过程中选择最优的$k$。

至于这个选择也并不难。把式子大力拆开就是

$\begin{equation}\left\{\begin{array}{lr}f[i][j]=(j-h[i])^2+min(f[i-1][k]-c*k+c*j)\ \ (k<j) &\\ f[i][j]=(j-h[i])^2+min(f[i-1][k]+c*k-c*j)\ \ (k>j)\end{array}\right.\end{equation}$

这样就可以分别从小到大和从大到小各枚举一遍,天然保证了$j,k$之间的大小顺序。

做法来源:题解 P2885 【[USACO07NOV]电话线Telephone Wire】

#include<bits/stdc++.h>
#define R register int
const int maxn = ;
const int INF = 0x3f3f3f3f; int n,c,mx,nw,ans,h[maxn];
int f[][]; inline int min(int a, int b){return a>b?b:a;}
int main()
{
memset(f, 0x3f3f3f3f, sizeof f);
scanf("%d%d",&n,&c), ans = INF;
for (R i=; i<=n; i++) scanf("%d",&h[i]), mx = mx>h[i]?mx:h[i];
for (R i=h[]; i<=mx; i++) f[][i] = (i-h[])*(i-h[]);
for (R i=; i<=n; i++)
{
R k = INF;
for (R j=h[i-]; j<=mx; j++)
{
k = min(k, f[nw^][j]-c*j);
if (j >= h[i]) f[nw][j] = k+c*j+(j-h[i])*(j-h[i]);
}
k = INF;
for (R j=mx; j>=h[i]; j--)
{
k = min(k, f[nw^][j]+c*j);
f[nw][j] = std::min(k-c*j+(h[i]-j)*(h[i]-j), f[nw][j]);
}
nw ^= ;
memset(f[nw], 0x3f3f3f3f, sizeof f[nw]);
}
for (R i=h[n]; i<=mx; i++)
ans = min(ans, f[nw^][i]);
printf("%d\n",ans);
return ;
}

END

【动态规划】bzoj1705: [Usaco2007 Nov]Telephone Wire 架设电话线的更多相关文章

  1. bzoj1705[Usaco2007 Nov]Telephone Wire 架设电话线(dp优化)

    1705: [Usaco2007 Nov]Telephone Wire 架设电话线 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 441  Solved: ...

  2. [bzoj1705] [Usaco2007 Nov]Telephone Wire 架设电话线

    正常DP.. f[i][j]表示前i个电线杆,把第i个电线杆高度改为j的最少总费用.设原来电线杆高度为h[] f[i][j]=min{ f[i-1][k]+C*|j-k|+(j-h[i])^2,(k& ...

  3. BZOJ_1705_[Usaco2007 Nov]Telephone Wire 架设电话线_DP

    BZOJ_1705_[Usaco2007 Nov]Telephone Wire 架设电话线_DP Description 最近,Farmer John的奶牛们越来越不满于牛棚里一塌糊涂的电话服务 于是 ...

  4. 【bzoj1705】[Usaco2007 Nov]Telephone Wire 架设电话线 dp

    题目描述 最近,Farmer John的奶牛们越来越不满于牛棚里一塌糊涂的电话服务 于是,她们要求FJ把那些老旧的电话线换成性能更好的新电话线. 新的电话线架设在已有的N(2 <= N < ...

  5. bzoj 1705;poj 3612:[Usaco2007 Nov]Telephone Wire 架设电话线

    Description 最近,Farmer John的奶牛们越来越不满于牛棚里一塌糊涂的电话服务 于是,她们要求FJ把那些老旧的电话线换成性能更好的新电话线. 新的电话线架设在已有的N(2 <= ...

  6. DP+滚动数组 || [Usaco2007 Nov]Telephone Wire 架设电话线 || BZOJ 1705 || Luogu P2885

    本来是懒得写题解的…想想还是要勤发题解和学习笔记…然后就滚过来写题解了. 题面:[USACO07NOV]电话线Telephone Wire 题解: F[ i ][ j ] 表示前 i 根电线杆,第 i ...

  7. bzoj 1705: [Usaco2007 Nov]Telephone Wire 架设电话线——dp

    Description 最近,Farmer John的奶牛们越来越不满于牛棚里一塌糊涂的电话服务 于是,她们要求FJ把那些老旧的电话线换成性能更好的新电话线. 新的电话线架设在已有的N(2 <= ...

  8. 【BZOJ】1705: [Usaco2007 Nov]Telephone Wire 架设电话线

    [题意]给定一排n根杆高度hi,一个常数C,杆升高x的代价为x^2,相邻两杆之间架设电话线代价为高度差*C,求总代价最小. [算法]DP+辅助数组优化 [题解]令f[i][j]表示第i根杆高度为j的最 ...

  9. BZOJ 1705: [Usaco2007 Nov]Telephone Wire 架设电话线 DP + 优化 + 推导

    Description 最近,Farmer John的奶牛们越来越不满于牛棚里一塌糊涂的电话服务 于是,她们要求FJ把那些老旧的电话线换成性能更好的新电话线. 新的电话线架设在已有的N(2 <= ...

随机推荐

  1. 原型设计模式(prototype

    # 什么是原型设计模式 > 这里与软件工程中的原型开发模式有那么一点类似的地方,我们首先需要构建出一个原型,这个原型可以在现实开发中抽象出来的具体类型,但是这个类型与具体的类又不同,需要抽取公共 ...

  2. TDH-常见运维指令

    1.查看cpu: cat /proc/cpuinfo | grep processor2.查看磁盘:df -h (查看磁盘使用率) df -i (查看iNode使用) fdisk -l (查看磁盘整体 ...

  3. ruby Iconv.iconv编码方法

    #定义一个UTF-8=>GBK的方法def encoding inStr    Iconv.iconv("GBK","UTF-8",inStr)end#定 ...

  4. 值类型 VS 引用类型~

    问     题 值  类  型 引 用 类 型 这个类型分配在哪里? 分配在栈上 分配在托管堆上 变量是怎么表示的? 值类型变量是局部复制 引用类型变量指向被分配得实例所占的内存 基类型是什么? 必须 ...

  5. vim的命令

    下面是从一个博客里摘抄出来的, 供自己学习使用.   在命令状态下对当前行用== (连按=两次), 或对多行用n==(n是自然数)表示自动缩进从当前行起的下面n行.你可以试试把代码缩进任意打乱再用n= ...

  6. 纪念Google Reader—Google Reader的最后一天

    从2006年到今天,几乎每天我都会打开Google Reader,但是今天不一样,因为它是最后一天.心情有些依依不舍,像是与一位多年老朋友永别.因此我非常痛恨Google,先给你送来个好朋友,再从你身 ...

  7. Android Doze模式源码分析

    科技的仿生学无处不在,给予我们启发.为了延长电池是使用寿命,google从蛇的冬眠中得到体会,那就是在某种情况下也让手机进入类冬眠的情况,从而引入了今天的主题,Doze模式,Doze中文是打盹儿,打盹 ...

  8. 自定义标签jsp2格式

    在写自定义标签时候是不是感觉很烦啊,其实人家也是这样认为的,于是我们的jsp新的标准对标签进行了更改,使我们用起来更简单.到底哪里简单呢?看看代码再说咯: 还是老规矩,先上一个标签的逻辑类: 1. p ...

  9. 不写画面的网页程序设计,Web API、Web Service、WCF Service

    客户有一个系统,经常要连上我方,查询数据 以前的作法是给对方一个账号,让他可以连上我们的DB来查询. 所以,早期的同仁,真的给他们DB链接字符串 客户的Windows程序.网站就真的靠这么危险的方式, ...

  10. python爬虫之路——基本文件操作

    介绍python如何打开文件和读取数据 新建TXT文档,为追加模式: f=open('c;/wendang/demo.txt','a+') content="abcdefg123456789 ...