E.Easy Climb

Somewhere in the neighborhood we have a very nice mountain that gives a splendid view over the surrounding area. There is one problem though: climbing this mountain is very difficult, because of rather large height differences. To make more people able to climb the mountain and enjoy the view, we would like to make the climb easier.

To do so, we will model the mountain as follows: the mountain consists of n adjacent stacks of stones, and each of the stacks is hi high. The successive height differences are therefore hi+1-hi (for 1 ≤ i ≤ n-1). We would like all absolute values of these height differences to be smaller than or equal to some number d.

We can do this by increasing or decreasing the height of some of the stacks. The first stack (the starting point) and the last stack (the ending point) should remain at the same height as they are initially. Since adding and removing stones requires a lot of effort, we would like to minimize the total number of added stones plus the total number of removed stones. What is this minimum number?

Input

On the first line one positive number: the number of testcases, at most 100. After that per testcase:
One line with two integers n (2 ≤ n ≤ 100) and d (0 ≤ d ≤ 109): the number of stacks of stones and the maximum allowed height difference.
One line with n integers hi (0 ≤ hi ≤ 109): the heights of the stacks.
Output

Per testcase:
One line with the minimum number of stones that have to be added or removed or “impossible” if it is impossible to achieve the goal.
Sample Input

3
10 2
4 5 10 6 6 9 4 7 9 8
3 1
6 4 0
4 2
3 0 6 3
Sample Output

6
impossible
4

The 2008 ACM Northwestern European Programming Contest

题意:给了n个堆的高度,要求改变堆的高度,首尾不可改变,使得队列的任意相邻的两数之差<=d,求最小代价

题解:

首先,如果数据范围很小的话 可以直接定义dp[i][j]表示处理完前i个高度后最后一个高度为b[j]的最小花费。 这样定义状态正确性是显而易见的。

然而 这里的d范围是10^9 显然不允许我们这么暴力的去枚举每一个状态。
所以需要去剪枝。 观察到最多只有100个高度, 却分布在1e9的范围里
肯定有很多状态是不会被用到的,应该要想到用离散化缩小范围。

首先,考虑只有3个值的情况:h1, h2, h3。那么根据题意,h2的范围应该在区间[h1-d,h1+d]和[h3-d,h3+d]的交集,即h1应该在[max(h1,h3)-d,min(h1,h3)+d]之间。如果这个区间是空集,即abs(h3-h1)>(3-1)*d,那么自然无解,否则:

1、如果h2就在区间内部,那么不需要修改;

2、如果h2<max(h1,h3)-d,那么就修改为交集的区间下界max(h1,h3)-d;

3、如果h2>min(h1,h3)+d,那么就修改为交集区间的上界min(h1,h3)+d。

可以发现,在这个简单的问题中,h2的最优修改方案只有这3种情况。并且我们还发现了,如果要修改,修改后的高度一定是如hp+k*d的形式。---离散化缩小范围

离散化缩小范围后呢,

下面需要想的就是状态转移方程了。

dp[i][j]=min(dp[i-1][k])+abs(x[j]-h[i]);// j-d<=k<=j+d;

一般单调队列有头,尾两个指针来维持单调性,这里只用一个头指针就完成普通单调队列的写法,在本题中 直接把b[] 数组当单调队列来用了
首先

具体做法是:

1.先维护窗口左边界,别让指针k超出了窗口,如果bk] < b[j] - d那么就k++ (因为b数组是从小到大已经排好序的),然后在不超出右边界b[j]+d 的前提下,如果dp[i][k+1] <= dp[i][k],那么k++;

为什么这样是对的的? 好像和之前说的优先队列一点也不一样啊! 其实是一样的操作,仔细回想维护优先队列时是怎么操作的 :用两个指针front、rear 先更新左边界,防止当前位置超出区间边界,一旦超出就front++; 然后每次新加进来一个值就要看看当前队列最右端的元素与新值的大小,如果大于新值那么就rear--,将无用的元素请出队列 ,直到小于新值,就将新值加入, 然而其实上边那个用一个指针的方法是如出一辙的,只不过将删除无用值这一步放到了求最小值时,也就是更新k时

         

#include<iostream>
#include<algorithm>
#include<math.h>
#define ll long long
#define mx 999999999999
using namespace std;
ll a[],b[],dp[][];// dp[i][j]表示 处理完前i座山后 最后一座山的高度为b[j]的最小花费;
int main()
{
int t;
cin>>t;
while(t--)
{
int n,d;
cin>>n>>d;
for(int i=;i<n;i++)
cin>>a[i];
if(abs(a[n-]-a[])>(n-)*d)
{
cout<<"impossible"<<endl;
continue;
}
ll cnt=;
for(int i=;i<n;i++)//离散化,处理后将山所有可能的改变值存在b数组
{
for(int j=;j<n;j++)
{
b[cnt++]=a[i]+j*d;
b[cnt++]=a[i]-j*d;
}
}
int m;
sort(b,b+cnt);
m=unique(b,b+cnt)-b;
for(int i=;i<m;i++)//初始化dp
{
dp[][i]=mx;
if(b[i]==a[])
dp[][i]=;
}
for(int i=;i<n;i++)
{
int k=;//单调队列头指针
for(int j=;j<m;j++)//如果山峰的高度要改变为b[k],那么b[k]的范围为[b[j]-d,b[j]+d],并且要达到最优,要么改变为b[k]-d,要么改变为b[k]+d
{
while(k<m&&b[k]<b[j]-d)//改变为区间下界值b[j]-d;找到b[k]>=b[j]-d就退出
k++;
while(k+<m&&b[k+]<=b[j]+d&&dp[i-][k+]<=dp[i-][k])//改变为区间上界值b[j]+d
k++;
if(dp[i-][k]==mx)
dp[i][j]=mx;
else
dp[i][j]=dp[i-][k]+abs(b[j]-a[i]);
}
}
for(int i=;i<m;i++)
{
if(b[i]==a[n-])
cout<<dp[n-][i]<<endl;
}
}
}

         

Easy Climb UVA - 12170 滚动dp +离散化+ 单调队列优化的更多相关文章

  1. 洛谷P3975 跳房子 [DP,单调队列优化,二分答案]

    题目传送门 跳房子 题目描述 跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一. 跳房子的游戏规则如下: 在地面上确定一个起点,然后在起点右侧画 n 个格子,这些格子都在同一 ...

  2. Codeforces 487B Strip (ST表+线段树维护DP 或 单调队列优化DP)

    题目链接 Strip 题意   把一个数列分成连续的$k$段,要求满足每一段内的元素最大值和最小值的差值不超过$s$, 同时每一段内的元素个数要大于等于$l$, 求$k$的最小值. 考虑$DP$ 设$ ...

  3. HDU 4374 One hundred layer DP的单调队列优化

    One hundred layer Problem Description   Now there is a game called the new man down 100th floor. The ...

  4. P2034 选择数字——线性dp(单调队列优化)

    选择数字 题目描述 给定一行 \(n\) 个非负整数 \(a[1]...a[n]\) .现在你可以选择其中若干个数,但不能有超过 \(k\) 个连续的数字被选择.你的任务是使得选出的数字的和最大. 输 ...

  5. ZOJ2067 经典 DP(单调队列优化)

    题目:一个由‘.’和‘#’组成矩形,统计里面'.'组成的矩形的个数. 点击打开链接 自己写挂了,懒得搞了 #include <stdio.h> #include <string.h& ...

  6. [小明打联盟][斜率/单调队列 优化dp][背包]

    链接:https://ac.nowcoder.com/acm/problem/14553来源:牛客网 题目描述 小明很喜欢打游戏,现在已知一个新英雄即将推出,他同样拥有四个技能,其中三个小技能的释放时 ...

  7. [BZOJ1044][HAOI2008]木棍分割 二分 + 单调队列优化dp + 滚动数组优化dp

    Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长 ...

  8. 2018.09.10 bzoj1499: [NOI2005]瑰丽华尔兹(单调队列优化dp)

    传送门 单调队列优化dp好题. 这题其实很简单. 我们很容易想到一个O(T∗n∗m)" role="presentation" style="position: ...

  9. bzoj 1499 [NOI2005]瑰丽华尔兹——单调队列优化dp

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1499 简单的单调队列优化dp.(然而当时却WA得不行.今天总算填了坑) 注意滚动数组赋初值应 ...

随机推荐

  1. windows下svn post-commit的实现

    前言: 好的!在结束了上一博客教程的Subversion安装之后.我们开始了下一项工作,windows版本下 svn post-commit的实现.说实话,这方面的知识网上的知识并不是很多~~~~~~ ...

  2. WebView 设置请求头 Header

    package com.webview.demo; 2 3 import android.os.Bundle; 4 import android.support.v7.app.AppCompatAct ...

  3. java垃圾回收学习

    经过一个晚上的努力终于完成了一个文件替换指定字符串的程序,但是由于我要替换的全站程序html文件太多, 所以eclipse下边老是在一个目录结束后报出java.lang.OutOfMemoryErro ...

  4. 设计模式课程 设计模式精讲 11-2 装饰者模式coding

    1 代码演练 1.1 代码演练1(未使用装饰者模式) 1.2 代码演练2(使用装饰者模式) 1 代码演练 1.1 代码演练1(未使用装饰者模式) 需求: 大妈下班卖煎饼,加一个鸡蛋加一元,一个火腿两元 ...

  5. Python - Mro

    参考 https://stackoverflow.com/questions/2010692/what-does-mro-do http://python.jobbole.com/85685/ 问题: ...

  6. django-文件上传Media url的配置

    一:问题 当开启一个项目的时候,通常会遇到文件(图片,音频等)上传的需要,最常见的比如图片的上传,用户头像,后台管理添加图片,而图片的在是数据库中的存储主要是以该文件的相对路径,在django中可以使 ...

  7. layer open type值类型

    参考:http://layer.layui.com/api.html layer提供了5种层类型: 0:信息框,默认 1:页面层 2:iframe层 3:加载层 4:tips层

  8. 02-01 Android学习进度报告一

    前两天,刚刚安装好有关Android开发有关的软件并配好了环境,有一些体会想要发表. 首先我了解到有一款专门用于Android开发的软件,叫做Android Studio ,是一个IDE集成软件 于是 ...

  9. python内置函数三

    ord()  函数 和 chr()  相反   chr() 是将数字转换成assci码     ord() 是将字符串转换成assci码 显示 pow() 函数  pow(x,y,z)  表示x**y ...

  10. python+ selenium + webdriver的环境准备

    web自动化安装 1.安装最新的selenium pip install -U selenium 2.安装chrom浏览器和chromdriver的下载 http://chromedriver.sto ...