可能是一类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. SpringBoot2.0 基础案例(03):配置系统全局异常映射处理

    一.异常分类 这里的异常分类从系统处理异常的角度看,主要分类两类:业务异常和系统异常. 1.业务异常 业务异常主要是一些可预见性异常,处理业务异常,用来提示用户的操作,提高系统的可操作性. 常见的业务 ...

  2. 出现提示ERROR 1289 The 'InnoDB' feature is disabled; you need MySQL built with 'InnoDB' to have IT working

    关闭mysql数据库 在mysql的安装目录中找到my.ini文件找到skip-innodb,在前面加上#号保存,重启mysql服务 OK.

  3. PAT甲级——1110 Complete Binary Tree (完全二叉树)

    此文章同步发布在CSDN上:https://blog.csdn.net/weixin_44385565/article/details/90317830   1110 Complete Binary ...

  4. 12.创建高级联结---SQL

    一.使用表别名 SQL除了可以对列名和计算字段使用别名,还允许给表名起别名.这样做有两个主要理由: 缩短SQL语句: 允许在一条SELECT语句中多次使用相同的表. SELECT cust_name, ...

  5. NET Core + Angular 2

    ASP.NET Core + Angular 2 Template for Visual Studio 2017-01-11 08:45 by 小白哥哥, 2069 阅读, 19 评论, 收藏, 编辑 ...

  6. Spark Mllib里如何提取每个字段并转换为***类型(图文详解)

    不多说,直接上干货! 具体,见 Hadoop+Spark大数据巨量分析与机器学习整合开发实战的第17章 决策树多元分类UCI Covertype数据集

  7. 表单验证插件jquery.validate.js

    最常使用JavaScript的场合就是表单的验证,而jQuery作为一个优秀的JavaScript库,也提供了一个优秀的表单验证插件----Validation.Validation是历史最悠久的jQ ...

  8. Web.config文件 详解

    一.认识Web.config文件Web.config 文件是一个XML文本文件,它用来储存 ASP.NET Web 应用程序的配置信息(如最常用的设置ASP.NET Web 应用程序的身份验证方式), ...

  9. 数据库2_sqlHelper

    封装一个受影响的行 public static int ExcuteNonQuery(string sqlText,params SqlParameter[] parameters) { using ...

  10. DHTMLX 使用汇总

    1.dhtmlxGrid  底部总出现滚动条 ------------------------------------------ 发现使用DHTMLXGRID时 GRID 底边总有   滚动条 测试 ...