P2893 [USACO08FEB]修路Making the Grade

题目描述

A straight dirt road connects two fields on FJ's farm, but it changes elevation more than FJ would like. His cows do not mind climbing up or down a single slope, but they are not fond of an alternating succession of hills and valleys. FJ would like to add and remove dirt from the road so that it becomes one monotonic slope (either sloping up or down).

You are given N integers A1, ... , AN (1 ≤ N ≤ 2,000) describing the elevation (0 ≤ Ai ≤ 1,000,000,000) at each of N equally-spaced positions along the road, starting at the first field and ending at the other. FJ would like to adjust these elevations to a new sequence B1, . ... , BN that is either nonincreasing or nondecreasing. Since it costs the same amount of money to add or remove dirt at any position along the road, the total cost of modifying the road is

|A1 - B1| + |A2 - B2| + ... + |AN - BN |Please compute the minimum cost of grading his road so it becomes a continuous slope. FJ happily informs you that signed 32-bit integers can certainly be used to compute the answer. 农夫约翰想改造一条路,原来的路的每一段海拔是A_i,修理后是B_i,花费|A_i – B_i|。我们要求修好的路是单调不升或者单调不降的。求最小花费。

输入输出格式

输入格式:

  • Line 1: A single integer: N

  • Lines 2..N+1: Line i+1 contains a single integer elevation: Ai

输出格式:

  • Line 1: A single integer that is the minimum cost for FJ to grade his dirt road so it becomes nonincreasing or nondecreasing in elevation.

这个题,从各种意义上讲都不难,然而我没想出来没想出来。。。

首先一定是要离散化的,因为不会去修一段没有出现的高度(可以证明这样不比最优解好)

设离散化以后的坐标,\(b[i]\)代表离散化以后排名为\(i\)的数字的值

\(dp[i][j]\)代表前\(i\)个组成的合法序列末尾元素的排名为\(j\)的最小花费

则有转移(单调不降)

\(dp[i][j]=min_{k=1}^j(dp[i][k]+abs(a[i]-b[j]))\)

显然可以前缀和优化一下子

复杂度\(O(N^2)\)


Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
const int N=2e3+10;
int dp[N][N],g[N][N],n,a[N],b[N];
int min(int x,int y){return x<y?x:y;}
int max(int x,int y){return x>y?x:y;}
int abs(int x){return x>0?x:-x;}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",a+i),b[i]=a[i];
std::sort(b+1,b+1+n);
memset(g,0x3f,sizeof(g));
memset(g[0],0,sizeof(g[0]));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
dp[i][j]=g[i-1][j]+abs(a[i]-b[j]);
g[i][j]=min(g[i][j-1],dp[i][j]);
}
int ans=g[n][n];
memset(g,0x3f,sizeof(g));
memset(g[0],0,sizeof(g[0]));
for(int i=1;i<=n;i++)
for(int j=n;j;j--)
{
dp[i][j]=g[i-1][j]+abs(a[i]-b[j]);
g[i][j]=min(g[i][j+1],dp[i][j]);
}
ans=min(ans,g[n][n]);
printf("%d\n",ans);
return 0;
}

事实上有一种更加神奇的做法

先说操作(单调非降的):

从左到右,把当前位置的数放进大根堆,然后比较这个数和堆顶的大小。

若比堆顶大,就不管

若比堆顶小,就把堆顶拿出来变成这个数,然后答案增加堆顶与这个数的差

代码大概是这样

for(int i=1;i<=n;i++)
{
scanf("%d",&a);
q.push(a);
if(a<q.top())
{
ans+=q.top()-a;
q.pop();
q.push(a);
}
}

为什么捏?

假设塞到第\(i\)了,前面是一个合法的递增序列,堆顶为\(y\),当前为\(x\)且\(x<y\)

这时候我们花掉了\(y-x\)块钱进行调整,考虑我们调整可以得到哪些结果

二元组\((x,x),(x+1,x+1),..(y-1,y-1),(y,y)\)都是可能的结果,虽然有的结果可能不合法,但一定存在合法的结果

我们尽可能想让当前的数值小,所以我们尽可能会选择小的合法结果

这时候我们发现,如果堆顶在后面被更新了,我们的合法结果的选择集合就变了

如果我们直接把最小的可能不合法的结果放进堆,那么当比它大的元素都被砍掉后(也就是它成了堆顶),它就变得合法了


2018.8.28

洛谷 P2893 [USACO08FEB]修路Making the Grade 解题报告的更多相关文章

  1. 【DP】+【贪心】【前缀和】洛谷P2893 [USACO08FEB]修路Making the Grade 题解

        正常的没想到的DP和玄学贪心. 题目描述 A straight dirt road connects two fields on FJ's farm, but it changes eleva ...

  2. 洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur 解题报告

    P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 约翰有\(n\)块草场,编号1到\(n\),这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可 ...

  3. 【洛谷】CYJian的水题大赛 解题报告

    点此进入比赛 \(T1\):八百标兵奔北坡 这应该是一道较水的送分题吧. 理论上来说,正解应该是DP.但是,.前缀和优化暴力就能过. 放上我比赛时打的暴力代码吧(\(hl666\)大佬说这种做法的均摊 ...

  4. 洛谷 P3143 [USACO16OPEN]钻石收藏家Diamond Collector 解题报告

    P3143 [USACO16OPEN]钻石收藏家Diamond Collector 题目描述 Bessie the cow, always a fan of shiny objects, has ta ...

  5. 洛谷 P1337 [JSOI2004]平衡点 / 吊打XXX 解题报告

    P1337 [JSOI2004]平衡点 / 吊打XXX 题目描述 有 \(n\) 个重物,每个重物系在一条足够长的绳子上.每条绳子自上而下穿过桌面上的洞,然后系在一起.\(X\)处就是公共的绳结.假设 ...

  6. 洛谷 P4151 [WC2011]最大XOR和路径 解题报告

    P4151 [WC2011]最大XOR和路径 题意 求无向带权图的最大异或路径 范围 思路还是很厉害的,上午想了好一会儿都不知道怎么做 先随便求出一颗生成树,然后每条返祖边都可以出现一个环,从的路径上 ...

  7. 洛谷 P3258 [JLOI2014]松鼠的新家 解题报告

    P3258 [JLOI2014]松鼠的新家 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他 ...

  8. 洛谷 P2420 让我们异或吧 解题报告

    P2420 让我们异或吧 题目描述 异或是一种神奇的运算,大部分人把它总结成不进位加法. 在生活中-xor运算也很常见.比如,对于一个问题的回答,是为1,否为0.那么: (A是否是男生 )xor( B ...

  9. 洛谷 P3102 [USACO14FEB]秘密代码Secret Code 解题报告

    P3102 [USACO14FEB]秘密代码Secret Code 题目描述 Farmer John has secret message that he wants to hide from his ...

随机推荐

  1. Asp.Net Core 使用Docker进行容器化部署(一)

    前几篇文章介绍了Liunx下的环境搭建,今天来分享一下.Net Core在Liunx上的部署. 我采用的方案是使用Dokcer作为运行虚拟机,Nginx作为Http服务器来进行反向代理,你可以理解为D ...

  2. C#正则表达式Regex类的使用

    C#中为正则表达式的使用提供了非常强大的功能,这就是Regex类.这个包包含于System.Text.RegularExpressions命名空间下面,而这个命名空间所在DLL基本上在所有的项目模板中 ...

  3. Hadoop(6)-HDFS的shell操作

    1.基本语法 使用 hadoop fs 具体命令   或者   hdfs dfs 具体命令 hadoop命令的shell源码 hdfs命令的shell源码 由此可见,这两个命令最后都是执行的一个jav ...

  4. Node.js 学习笔记 (一) 安装配置

    Node.js 安装配置 本安装教程以Node.js v4.4.3 LTS(长期支持版本)版本为例 Window 上安装Node.js 你可以采用以下两种方式来安装. 1.Windows 安装包(.m ...

  5. haproxy + keepalived 实现高可用负载均衡集群

    1. 首先准备两台tomcat机器,作为集群的单点server. 第一台: 1)tomcat,需要Java的支持,所以同样要安装Java环境. 安装非常简单. tar xf  jdk-7u65-lin ...

  6. unity独立游戏开发日志2018/09/26

    最近太忙,今天吃饭的时候灵感一现...想到了随机地图生成的方法,不过可能实现的比较笨...还需要优化,大佬绕过. 注释没打,最后统一解释. using System.Collections; usin ...

  7. C++代码理解 (强制指针转换)

    #include<iostream> using namespace std; class A { public: A() { a=; b=; c=; f=; } private: int ...

  8. 1826: [JSOI2010]缓存交换

    1826: [JSOI2010]缓存交换 https://www.lydsy.com/JudgeOnline/problem.php?id=1826 分析: 简单的贪心,然后调啊调...最近怎么了,码 ...

  9. 用Kettle的一套流程完成对整个数据库迁移 费元星

    原地址 :http://ainidehsj.iteye.com/blog/1735434 需求: 1.你是否遇到了需要将mysql数据库中的所有表与数据迁移到Oracle. 2.你是否还在使用kett ...

  10. python基础——重访类型分类

    python基础--重访类型分类 对象根据分类来共享操作:例如,字符串.列表和元组都共享诸如合并.长度和索引等序列操作. 只有可变对象(列表.字典和集合)可以原处修改:我们不能原处修改数字,字符串.元 ...