洛谷1440 求m区间内的最小值

本题地址:http://www.luogu.org/problem/show?pid=1440

题目描述

一个含有n项的数列(n<=2000000),求出每一项前的m个数到它这个区间内的最小值。若前面的数不足m项则从第1个数开始,若前面没有数则输出0。

输入输出格式

输入格式:

第一行两个数n,m。
第二行,n个正整数,为所给定的数列。

输出格式:

n行,第i行的一个数ai,为所求序列中第i个数前m个数的最小值。

输入输出样例

输入样例#1:

6 2

7 8 1 4 3 2

输出样例#1:

0

7

7

1

1

3

说明

【数据规模】
m≤n≤2000000

【思路】

单调队列。

题目比较裸,直接用一个单调队列维护即可。单调队列第一次写,总结有如下需要注意的地方:

1、  
注意维护的是什么,本题中维护的是一个满足序号 >=i-m+1 的序列,其中序列满足a值单调递增。

2、  
注意边界,特别是初始情况下是否满足平凡情况。

3、  
注意单调队列的维护添加
与取值之间的顺序,取决于使用单调队列的目的。

还有需要注意的是题目中要求i之前m个,每次取值是算上当前a的所以需要错开一个。

【代码】

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4
 5 const int maxn = 2000000+10;
 6
 7 int a[maxn],que[maxn],d[maxn];
 8 int n,m,front,rear;
 9
10 inline int read_int() {
11     char c; c=getchar();
12     while(!isdigit(c)) c=getchar();
13
14     int x=0;
15     while(isdigit(c)) {
16         x=x*10+c-‘0‘;
17         c=getchar();
18     }
19     return x;
20 }
21
22 int main() {
23     n=read_int(); m=read_int();
24     a[0]=1<<30;               //边界不取
25     front=rear=1;
26     for(int i=1;i<=n;i++)
27     {
28         a[i]=read_int();
29
30         //注意顺序
31         while(front<=rear && (que[front]<(i-m+1))) front++;
32
33         while(front<=rear && a[i]<=a[que[rear]]) rear--;  //注意维护a值最小的
34
35         que[++rear]=i;
36
37         d[i]=a[que[front]];
38
39     }
40     cout<<0<<"\n";
41     for(int i=1;i<n;i++) cout<<d[i]<<"\n";
42     return 0;
43 }
时间: 2024-10-10 20:23:52

洛谷1440 求m区间内的最小值的相关文章

[洛谷P1440]求m区间内的最小值

题目大意:给你n个数,求出每个数前m位的最小值 题解:单调队列,用一个可以双向弹出的队列来存一串数,满足里面的数具有单调性,我们可以假设它是单调递增的,即求最小的数.那么可以把要插入的这个数与队尾元素比较,如果队尾的数大,那么插入它就不满足单调性了,那么我们就从队尾删除元素,直到比队尾元素大.这样就可以满足要求.如果队首元素已经超出了m的范围,就从队首删除元素,队首的元素就一直是答案. #include<cstdio> using namespace std; int n,m; int q[2

单调队列——求m区间内的最小值

单调队列,顾名思义是指队列内的元素是有序的,队头为当前的最大值(单调递减队列)或最小值(单调递增序列),以单调递减队列为例来看队列的入队和出队操作: 1.入队: 如果当前元素要进队,把当前元素和队尾元素比较,如果当前元素小于队尾元素,那么当前元素直接进队,如果当前元素大于队尾元素,那么队尾出队,将当前元素和新的队尾再做比较,直到当前元素大于队尾元素或者队列为空.单调队列只能在队尾插入元素,队尾和队头都可以删除元素. 2.出队: 出队直接取队头即可,因为用单调队列就是为了取最值,而队头就是最值.

P1886 滑动窗口&amp;&amp;P1440 求m区间内的最小值

单调队列入门题 P1440 求m区间内的最小值 题目描述 一个含有n项的数列(n<=2000000),求出每一项前的m个数到它这个区间内的最小值.若前面的数不足m项则从第1个数开始,若前面没有数则输出0. 输入输出格式 输入格式: 第一行两个数n,m. 第二行,n个正整数,为所给定的数列. 输出格式: n行,第i行的一个数ai,为所求序列中第i个数前m个数的最小值. 输入输出样例 输入样例#1: 复制 6 2 7 8 1 4 3 2 输出样例#1: 复制 0 7 7 1 1 3 说明 [数据规模

luogu P1440 求m区间内的最小值

题目描述 一个含有n项的数列(n<=2000000),求出每一项前的m个数到它这个区间内的最小值.若前面的数不足m项则从第1个数开始,若前面没有数则输出0. 输入输出格式 输入格式: 第一行两个数n,m. 第二行,n个正整数,为所给定的数列. 输出格式: n行,第i行的一个数ai,为所求序列中第i个数前m个数的最小值. 输入输出样例 输入样例#1: 6 2 7 8 1 4 3 2 输出样例#1: 0 7 7 1 1 3 说明 [数据规模] m≤n≤2000000 线段树 维护最小值 #inclu

求m区间内的最小值(洛谷_1440)

这题用队列随便搞一下就好了. 就是可能有些细节 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; inline int read(){ int t=1,num=0;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();} while(

P1440 求m区间内的最小值

第二道单调队列. 这道题就是经典的滑动窗口问题了.要求你求某一个数的前\(m\)位中的最小元素. 先说一句话:单调队列中,队首保存的是最优解,其实是次解,以此类推. 所以我们可以构造一个上升的单调队列,队首弄出来的就是答案. 元素的加入不用说,就是那样子. 重点是这里多了元素的删除.因为窗口的长度有限,你需要把当前窗口没有覆盖住的那些点给pop掉. 可以发现,你要删除的点一定是在队首!并且每一个时刻的最优解也还是队首. 我们只需要加入一个点的同时记录它的加入时间,然后判断是否合法即可. 不知道是

luoguP1440 求m区间内的最小值

emmmmmm 看到这道题的第一反应嘛 (区间最小,大概是RMQ吧 然后,华丽丽的80分 (题解说st表会T两个点,可是我是MLE emmmm... 貌似st表不能做,有一个滚动数组的优化,可以看看题解学一下 这里我改用了单调队列的做法 (本来用的STL的队列,但是学长说不方便,开一个数组即可 [而且我STL队列还没写出来23333 emmmm(不知道怎么讲 看代码吧 #include<cstdio> using namespace std; const int maxn = 2000010;

2017乌鲁木齐区域赛K(容斥原理【求指定区间内与n互素的数的个数】)

#include<bits/stdc++.h>using namespace std;const long long mod = 998244353;typedef const long long ll;vector<long long>p;long long inv(long long x,long long y)//快速幂求逆元模板(以乘代除){    long long r=1;    while(y>0)    {        if(y&1)        

洛谷P1220关路灯[区间DP]

题目描述 某一村庄在一条路线上安装了n盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少).老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯. 为了给村里节省电费,老张记录下了每盏路灯的位置和功率,他每次关灯时也都是尽快地去关,但是老张不知道怎样去关灯才能够最节省电.他每天都是在天亮时首先关掉自己所处位置的路灯,然后可以向左也可以向右去关灯.开始他以为先算一下左边路灯的总功率再算一下右边路灯的总功率,然后选择先关掉功率大的一边,再回过头来关掉另一边