▎前言

  首先先来说一下RMB是什么,当然是人民币啦。

  今天我们要学的这个东西不一般,叫做RMQ问题,那么它和RMB有什么关系呢?待小编细细说来。

▎前置技能:动态规划

  不会的同志请戳这里迅速了解动态规划

▎RMQ问题是什么

☞『定义』

  RMQ (Range Minimum/Maximum Query)问题是指:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题。(copy自百度)

  猜你也不想看,来,小编用人话翻译一下:就是说给定一堆数字(顺序位置固定且永远不变),(多次)询问你一段区间内的最大/最小值。

☞『问题解决:模拟算法』

  RMQ只是一类这样的问题,却不是一门算法。

  既然是问题,那么我们就应该解决,但是怎么解决,怎样解决,一切先从模拟算法(直白一点叫暴力)说起。

  先来想想模拟算法怎么解决,当然是给定区间后直接遍历,寻找最大/最小值呗。但是别忘了,这种题多次询问,一直遍历对于数据规模大的题简直是杯水车薪。

  此时,不得不请出动态规划。

☞『问题解决:动态规划』

  我们为什么使用动态规划呢?先来思考这个问题:为什么暴力不能满足需求。

  你肯定会说:这还不简单,暴力慢呗。

  但是暴力究竟慢在了哪里?暴力慢在了没有完全利用好整个大区间,很多东西都在重复遍历。

  那么什么东西能很好的利用大区间呢?我们就会自然的想到了动态规划(感觉属于区间动态规划)。

  既然多次询问,那么就变向的告诉了我们一定要预处理,这里我们的动态规划可以O(n log n)预处理,然后O(1)查询。

  先来思考怎么设计状态,最开始小编是这样想的,既然是区间型动态规划类问题,那么就让f[i][j]表示i~j区间内的最大/最小数吧,(以最大数为例)状态转移方程自然就是f[i][j]=max(f[i][k],f[k+1][j])。(k为随机一个i~j区间的数组下标,不过小编更喜欢取中点)

  后来发现一本通提高篇上的设计状态更好,更快捷,我设计的太慢了。一本通提高篇上是这样处理的:f[i][j]表示i~2j-1区间内的最大/最小数,那么我们可以仿照之前我的想法,分一半,就是这样的:

  

  从区间初始和结束位置改成动态规划的形式后就是这样的:f[i][j-1]和f[i+2j-1][j-1],有时候奇数和偶数是不一样的,所以小编的图可能对这两个式子来说不太标准。

  那么我们要求的最大最小值就很简单了。

  但是问题又来了,我们如何面对询问呢?

  我们可以以二为底,将这个区间内数字的个数次方(幂的逆运算)为界,进行比较两个区间大小,图解一下:

  

  那么我们就只要比较出两个区间中的最大最小值即可。两个区间改成动态规划形式就是f[x][log[d]],f[y-(1<<log[d])+1][log[d]]),其中我把d改成了y-x+1的意思。

  好了,问题又来了,log怎么处理,我们先来看一下前10个数的log处理情况:

  

  经过专业调查和探寻后,就会发现log[i]=log[i/2]+1的规律,因此我们可以预处理出log的值。

☞『这么快的算法,为什么还需要其他算法呢?』

  其实这个问题正是这个算法的弊端,因为不能支持期间修改一些数的值。

  而线段树,树状数组正巧妙的解决了这一弊端。

▎实战演练:洛谷P1816 忠诚(模板题)

  废话不多说,直接上题:


P1816 忠诚

题目描述

老管家是一个聪明能干的人。他为财主工作了整整10年,财主为了让自已账目更加清楚。要求管家每天记k次账,由于管家聪明能干,因而管家总是让财主十分满意。但是由于一些人的挑拨,财主还是对管家产生了怀疑。于是他决定用一种特别的方法来判断管家的忠诚,他把每次的账目按1,2,3…编号,然后不定时的问管家问题,问题是这样的:在a到b号账中最少的一笔是多少?为了让管家没时间作假他总是一次问多个问题。

输入输出格式

输入格式:

输入中第一行有两个数m,n表示有m(m<=100000)笔账,n表示有n个问题,n<=100000。

第二行为m个数,分别是账目的钱数

后面n行分别是n个问题,每行有2个数字说明开始结束的账目编号。

输出格式:

输出文件中为每个问题的答案。具体查看样例。

输入输出样例

输入样例#1: 复制

10 3
1 2 3 4 5 6 7 8 9 10
2 7
3 9
1 10
输出样例#1: 复制

2 3 1

  这道题相当好做,就是模板题,所以就不解释了,直接上代码:

 #include<iostream>
using namespace std;
int m,n,a[],f[][],x,y,log[];
int main()
{
cin>>m>>n;
for(int i=;i<=m;i++)
{
cin>>a[i];
f[i][]=a[i];
}
for(int j=;j<=;j++)
for(int i=;i+(<<j)-<=m;i++)
f[i][j]=min(f[i][j-],f[i+(<<(j-))][j-]);
log[]=;
for(int i=;i<=;i++)
log[i]=log[i/]+;
for(int i=;i<=n;i++)
{
cin>>x>>y;
int d=y-x+;
cout<<min(f[x][log[d]],f[y-(<<log[d])+][log[d]])<<" ";
}
return ;
}

▎实战演练:一本通1541:【例 1】数列区间最大值(模板题)

  废话不多说,直接上题:


1541:【例 1】数列区间最大值

时间限制: 1000 ms         内存限制: 524288 KB
提交数: 638     通过数: 224

【题目描述】

输入一串数字,给你 M 个询问,每次询问就给你两个数字 X,Y,要求你说出 X 到 Y 这段区间内的最大数。

【输入】

第一行两个整数 N,M 表示数字的个数和要询问的次数;

接下来一行为 N 个数;

接下来 M 行,每行都有两个整数 X,Y。

【输出】

输出共 M 行,每行输出一个数。

【输入样例】

10 2
3 2 4 5 6 8 1 2 9 7
1 4
3 8

【输出样例】

5
8

【提示】

数据范围与提示:

对于全部数据,1≤N≤105,1≤M≤106,1≤X≤Y≤N。数字不超过 C/C++ 的 int 范围。

【来源】

  这道题只要把忠诚的代码改成max就可以了(还稍微有点其他细节),注意会卡常数,不能用cin和cout。代码如下:

  

 #include<iostream>
#include<cstdio>
using namespace std;
int m,n,a[],f[][],x,y,log[];
int main()
{
scanf("%d%d",&m,&n);
for(int i=;i<=m;i++)
{
scanf("%d",&a[i]);
f[i][]=a[i];
}
for(int j=;j<=;j++)
for(int i=;i+(<<j)-<=m;i++)
f[i][j]=max(f[i][j-],f[i+(<<(j-))][j-]);
log[]=;
for(int i=;i<=m;i++)
log[i]=log[i>>]+;
for(int i=;i<=n;i++)
{
scanf("%d%d",&x,&y);
int d=y-x+;
printf("%d \n",max(f[x][log[d]],f[y-(<<log[d])+][log[d]])) ;
}
return ;
}

【算法•日更•第十九期】动态规划:RMQ问题的更多相关文章

  1. 【算法•日更•第二十八期】图论:强连通+Tarjan算法(一)

    ▎前言 一直都想学习这个东西,以为很难,结果发现也不过如此. 只要会些图论的基础就可以了. ▎强连通 ☞『定义』 既然叫强连通,那么一定具有很强的连通性. 强连通:就是指在一个有向图中,两个顶点可以互 ...

  2. 【算法•日更•第十期】树型动态规划&区间动态规划:加分二叉树题解

    废话不多说,直接上题: 1580:加分二叉树 时间限制: 1000 ms         内存限制: 524288 KB提交数: 121     通过数: 91 [题目描述] 原题来自:NOIP 20 ...

  3. 【算法•日更•第二十三期】数据结构:two-pointer(尺取法)&莫队

    ▎引入 ☞『例题』 一道十分easy的题: 洛谷P1638 长度为n的序列,m种数 找一个最短区间,使得所有数出现一遍 n≤1e6 ,m≤2e3. ☞『分析』 这道题非常的简单,但是如果不会two-p ...

  4. 【算法•日更•第十二期】信息奥赛一本通1585:【例 1】Amount of Degrees题解

    废话不多说,直接上题: 1585: [例 1]Amount of Degrees 时间限制: 1000 ms         内存限制: 524288 KB提交数: 130     通过数: 68 [ ...

  5. 【算法•日更•第三十七期】A*寻路算法

    ▎写在前面 这是一种搜索算法,小编以前总是念成A乘寻路算法,没想到一直念错. 请大家都念成A星寻路算法,不要像小编一样丢人了. ▎A*寻路算法 ☞『引入』 相信大家都或多或少的玩过一些游戏吧,那么游戏 ...

  6. 【算法•日更•第四十七期】Mac与windows系统的差别

    小编最近装了个Mac系统,因为小编已经有笔记本可以用linux了,所以就决定在台式机上装个双系统,结果一不小心把Mac装在C盘上了,哎,说多了都是泪啊. 其实用了Mac之后才发现windows特别好用 ...

  7. 【算法•日更•第五十七期】快速傅里叶变换(FFT):从入门到放弃

    ▎一些用的上的东西 小编太菜了,很多东西都不会证明(主要是三角函数还没有学啊~~~). 附上链接https://blog.csdn.net/enjoy_pascal/article/details/8 ...

  8. 【算法•日更•第三十期】区间动态规划:洛谷P4170 [CQOI2007]涂色题解

    废话不多说,直接上题:  P4170 [CQOI2007]涂色 题目描述 假设你有一条长度为5的木版,初始时没有涂过任何颜色.你希望把它的5个单位长度分别涂上红.绿.蓝.绿.红色,用一个长度为5的字符 ...

  9. 【算法•日更•第三十九期】迭代加深搜索:洛谷SP7579 YOKOF - Power Calculus 题解

    废话不多说,直接上题: SP7579 YOKOF - Power Calculus 题意翻译 (略过没有营养的题干) 题目大意: 给出正整数n,若只能使用乘法或除法,输出使x经过运算(自己乘或除自己, ...

随机推荐

  1. 修改用户名后TSF出现"需要本地工作区。工作区 xxx 并未驻留在本计算机上"

    解决方法就是:1,打开vs下的"开发人员命令提示"2,按下面格式输入命令:tf workspaces /collection:http://192.168.0.110:8080/t ...

  2. coci2018 题解

    plahte 给定一些矩形和一些有颜色的点,求每个矩形上有多少种颜色的点,保证矩形只有包含和不相交两种关系,规模 \(10^5\). 把每个矩形看成一个点,用扫描线建出森林,同时也顺便处理点. 然后做 ...

  3. 大神为你分析 Go、Java、C 等主流编程语言(Go可以替代Java,而且最小化程序员的工作量,学习比较容易)

    本文主要分析 C.C++98.C++11.Java 与 Go,主要论述语言的关键能力.在论述的过程中会结合华为各语言编程专家和华为电信软件内部的骨干开发人员的交流,摒弃语言偏好或者语言教派之争,尽量以 ...

  4. SYN6105型 GPS子钟

    SYN6105型 GPS子钟 产品概述 SYN6105型GPS子钟是由西安同步电子科技有限公司精心设计.自行研发生产的一套以接收GPS卫星信号的子钟,从GPS地球同步卫星上获取标准时钟信号信息将这些时 ...

  5. DNS查询命令

    dig(domain information groper)是一个在类Unix命令行模式下查询DNS,包括NS记录,A记录,MX记录等相关信息的工具 一.简单介绍使用dig命令查询DNS的方法 dig ...

  6. java中更新文件时,指定原文件的编码格式,防止编码格式不对,造成乱码

    1.pom中添加引入cpdetector(一个可以自动检测文本编码格式的项目) //pom中添加引入cpdetector(一个可以自动检测文本编码格式的项目) <dependency> & ...

  7. 编译gd库出错

    不知道大家有没有遇到在  X64 RedHat5 或者 RedHat4 下.编译安装PHP环境的时候. 安装了libxml,zlib,jpeg,libpng,freetype,libart_lgpl, ...

  8. 为什么建议大家使用 Linux 开发

    Linux 能用吗? 我身边还有些朋友对 linux 的印象似乎还停留在黑乎乎的命令行界面上.当我告诉他或者建议他使用 linux 时,会一脸惊讶的问我,那个怎么用(来开发或者日常使用)? Linux ...

  9. 使用vue-print-nb插件页面空白以及打印没有样式问题

    在使用vue-print-nb中遇到两个问题: 第一个问题:点击打印后,打印的内容是一片空白 vue-print-nb的原理大概是在你的页面上创建一个iframe,然后把你要打印的那一个div抓出来给 ...

  10. 并发编程-concurrent指南-线程池ExecutorService的实例

    1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable() { @Override public void run() { ...