正常的没想到的DP和玄学贪心。

题目描述

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 \(A_1, ... , A_N (1 \le N \le 2,000)\) describing the elevation \( (0 \le A_i \le 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 \(B_1, ... , B_N\) 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 \(|A_1-B_1|+|A_2-B_2|+...+|A_N-B_N|\)

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: \(A_i\)

输出格式:

* 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.

输入输出样例

输入样例#1:

7
1
3
2
4
5
3
9
输出样例#1:

3

题解 of DP:

    首先这个题有一个比较正常的DP做法,但是长时间的思维定式会让人不敢朝这里想。

    看到\(2,000\)的数据范围,可以联想到的复杂度是\(O(n^2),O(n^2\log n)\)等,因此考虑DP或递推。状态如果从前面所有段转移过来,感觉不太现实,而且不容易处理。不过我们手玩发现,把一段路的高度改为没有修改过的是最优的一种方案。因此把一开始的数据离散化,得到不超过\(n\)个数。

    考虑DP,f[i][j]表示到第i段路满足不下降(只做不下降,不上升待会再做一遍),且当前高度为j所需要的最小花费。它的转移实际上是\(\min\limits_{k\in[1,j]}{f[i-1][k]}+|h[i]-ori[j]|\),ori[j]是j对应的离散化之前的数,h[i]是i原来的高度,因为不下降,所以只能从\([1,j]\)转移。不过这样的复杂度是\(O(n^3)\)的,我们发现,随着\(j\)的增大,\(k\)的取值范围只是上界变大了,因此可以通过更新前缀和来维护\(minn[i]=\min\limits_{j=[1,i]}\{ f[j]\}\)。

    同时,因为循环\(1-n\)在最外层,所以那层可以滚掉,同时f数组就可以直接更新前缀和,因此也不用额外开一个数组了。

Code of DP:

#include<cstdio>
#include<cstring>
#include<algorithm>
long long Abs(long long x)
{
return x>0?x:(-x);
}
long long Min(long long x,long long y)
{
return x<y?x:y;
}
struct node
{
long long a,b,i;
friend bool operator <(node x,node y)
{
return x.i<y.i;
}
}a[2001];
bool cmp(node x,node y)
{
return x.a<y.a;
}
long long ori[2001];
long long f[2001];//f[i]代表f[i]到f[n]的最大值
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i].a);
a[i].i=i;
} std::sort(a+1,a+n+1,cmp);
int cnt=0;
a[0].a=-1;
for(int i=1;i<=n;++i)
{
if(a[i].a!=a[i-1].a)
{
++cnt;
ori[cnt]=a[i].a;
}
a[i].b=cnt;
}
std::sort(a+1,a+1+n); long long ans=1000000000000000ll; memset(f,0,sizeof(f));
f[cnt+1]=10000000000000ll;
for(int i=n;i;--i)
{
for(int j=1;j<=cnt;++j)
f[j]+=Abs(a[i].a-ori[j]);
for(int j=cnt;j;--j)
f[j]=Min(f[j],f[j+1]);
}
for(int i=1;i<=cnt;++i)
ans=ans<f[i]?ans:f[i];
printf("%lld\n",ans);
return 0;
}

题解 of 贪心:

    在翻最优解代码时,发现了一种玄学贪心,用了堆优化,时间复杂度是\(O(n\log n)\),分析了很久感觉算法是对的但是不知道是什么原理。后来@Dew推出来了应该是正确的思路。

    对于维护从左到右的不下降性质,可以用一个大根堆。假设当前做到第\(i\)段,前面的\(1-i-1\)段都已经保证了不下降性质,每一段的高度都被放在了堆里,那么如果现在插入了一个数不满足不下降性质,我们就从大根堆里取出堆顶\(x\)。我们知道,要使\(a_i\)和\(x\)这两个元素满足不下降,所要付出的代价至少是\(|a_i-x|\)。而我们可以发现,对于两个数,假设是5和2,我们付出\(|a_i-x|=3\)的代价可以使这两个数满足不下降这几种中的任意一种:\(\{5,5\},\{4,4\},\{3,3\},\{2,2\}\),由于贪心,我们把5取出来,把\(\{2,2\}\)放进去,并计算一个3的代价,这个代价是必须的。不过现在序列可能变成了\(\{1,3,4,2,2\}\),它好像不满足不下降了。

    不过我们心里要明白,最后的\(\{2,2\}\)是活动的,可以换成\(\{4,4\}\)或\(\{5,5\}\),\(\{2,2\}\)只是一个下界。而我们把5这个“障碍”移开了,如果接下来再出现小于4的,就可以把4的位置换成新来的元素,而不论怎样,因为他们可以被替换,所以还是维持了不下降的性质。而因为5被替换后,4成了最大的,所以那些活动的元素上界就成了4,此时满足以4结尾的不下降序列。

Code of greedy:(虽然都是ms级的

#include<cstdio>
#include<queue>
using std::priority_queue;
priority_queue<int> q;
priority_queue<int> q1;
int a[2010];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]); long long sum=0,ans=0;
for(int i=1;i<=n;++i)
{
q.push(a[i]);
if(q.top()>a[i])//a[i]不是最大的,就需要调整
{
sum+=q.top()-a[i];
q.pop();
q.push(a[i]);
}
}
ans=sum;
sum=0;
for(int i=n;i;--i)
{
q1.push(a[i]);
if(q1.top()>a[i])
{
sum+=q1.top()-a[i];
q1.pop();
q1.push(a[i]);
}
}
printf("%lld\n",ans<sum?ans:sum);
return 0;
}

【DP】+【贪心】【前缀和】洛谷P2893 [USACO08FEB]修路Making the Grade 题解的更多相关文章

  1. 洛谷 P2893 [USACO08FEB]修路Making the Grade 解题报告

    P2893 [USACO08FEB]修路Making the Grade 题目描述 A straight dirt road connects two fields on FJ's farm, but ...

  2. 洛谷P1484 种树&洛谷P3620 [APIO/CTSC 2007]数据备份 题解(堆+贪心)

    洛谷P1484 种树&洛谷P3620 [APIO/CTSC 2007]数据备份 题解(堆+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/132 ...

  3. [USACO08FEB]修路Making the Grade

    [USACO08FEB]修路Making the Grade比较难的dp,比赛时打的找LIS,然后其他的尽可能靠近,40分.先举个例子61 2 3 1 4 561 2 3 3 4 5第4个1要么改成3 ...

  4. P2893 [USACO08FEB]修路

    直入主题. 农夫约翰想改造一条路,原来的路的每一段海拔是Ai,修理后是Bi花费|A_i–B_i|.我们要求修好的路是单调不升或者单调不降的.求最小花费. 数据范围:n<=2000,0≤ Ai ≤ ...

  5. 洛谷P3387 【模板】缩点 题解

    背景 今天\(loj\)挂了,于是就有了闲情雅致来刷\(luogu\) 题面 洛谷P3387 [模板]缩点传送门 题意 给定一个\(n\)个点\(m\)条边有向图,每个点有一个权值,求一条路径,使路径 ...

  6. BZOJ3675 & 洛谷3648 & UOJ104:[Apio2014]序列分割——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=3675 https://www.luogu.org/problemnew/show/P3648 ht ...

  7. 洛谷 P2949 [USACO09OPEN]工作调度Work Scheduling 题解

    P2949 [USACO09OPEN]工作调度Work Scheduling 题目描述 Farmer John has so very many jobs to do! In order to run ...

  8. [NOI导刊2010提高&洛谷P1774]最接近神的人 题解(树状数组求逆序对)

    [NOI导刊2010提高&洛谷P1774]最接近神的人 Description 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某 ...

  9. [洛谷P1029]最大公约数与最小公倍数问题 题解(辗转相除法求GCD)

    [洛谷P1029]最大公约数与最小公倍数问题 Description 输入二个正整数x0,y0(2<=x0<100000,2<=y0<=1000000),求出满足下列条件的P, ...

随机推荐

  1. TOP命令 详解CPU 查看多个核心的利用率按1

    top命令是linux下常用的工具,可以查看各个进程的CPU使用情况.先看一个实例: 这是Ramnode双核VPS的top显示结果: 左上角可以看到CPU的使用率是11.3%,但是看下面的进程,plu ...

  2. 264E Roadside Trees

    传送门 题目大意 分析 倒着跑LIS表示以i为开头的LIS,于是对于删除可以暴力重算前10棵树.而对于种树,因为高度不超过10且高度两两不同,所以暴力重算比它矮的10棵树即可.对于需要重算的点,将其从 ...

  3. swing中的分层

    swing中的分层 摘自:https://blog.csdn.net/levelmini/article/details/26692205 2014年05月23日 12:42:56 阅读数:1244 ...

  4. 手机APP兼容性测试

    兼容性测试方案 兼容性问题 屏幕分辨率兼容性问题 软件(iOS和Android系统版本及不同厂家的定制ROM)兼容性问题 硬件(不同的CPU.内存大小等等)兼容性问题 网络(2G/3G/4G/WIFI ...

  5. Java 扫描器类 Scanner类

    1.Scanner是SDK1.5新增的一个类,可是使用该类创建一个对象.Scanner reader=new Scanner(System.in); 2.reader对象调用下列方法(函数),读取用户 ...

  6. touchmove和touchend的使用

    touchstart:当手指触摸屏幕时触发:即使已经有一个手指放在了屏幕上也会触发.touchmove:当手指在屏幕上滑动时连续的触发.在这个事件发生期间,调用preventDefault()可阻止滚 ...

  7. Linux 命令之chmod

    立贴今日吉,不断更新,欢迎斧正,支持为感! 1. chmod --权限控制 chmod [-cfvR] [--help] [--version] mode file... 说明 : Linux/Uni ...

  8. ComicEnhancerPro 系列教程十八:JPG文件长度与质量

    作者:马健邮箱:stronghorse_mj@hotmail.com 主页:http://www.comicer.com/stronghorse/ 发布:2017.07.23 教程十八:JPG文件长度 ...

  9. angular 管道

    import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'multi' }) export class MultiPipe ...

  10. 编码原则实例------c++程序设计原理与实践(进阶篇)

    编码原则: 一般原则 预处理原则 命名和布局原则 类原则 函数和表达式原则 硬实时原则 关键系统原则 (硬实时原则.关键系统原则仅用于硬实时和关键系统程序设计) (严格原则都用一个大写字母R及其编号标 ...