首页 > 其他分享 >007. 求m区间内的最小值(洛谷P1440)

007. 求m区间内的最小值(洛谷P1440)

时间:2024-12-28 20:19:21浏览次数:6  
标签:ch 洛谷 val P1440 min int while 007 include

007. 求m区间内的最小值(洛谷P1440)

题目描述

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

输入格式

第一行两个整数,分别表示 \(n\),\(m\)。

第二行,\(n\) 个正整数,为所给定的数列 \(a_i\)。

输出格式

\(n\) 行,每行一个整数,第 \(i\) 个数为序列中 \(a_i\) 之前 \(m\) 个数的最小值。

样例 #1

样例输入 #1

6 2
7 8 1 4 3 2

样例输出 #1

0
7
7
1
1
3

提示

对于 \(100\%\) 的数据,保证 \(1\le m\le n\le2\times10^6\),\(1\le a_i\le3\times10^7\)。

题解

单调队列嘛,就是单调的队列
单调递增或者单调递减
所以说答案(也就是最优解)就存在队首,而队尾则是最后进队的元素
那么怎么判断这个数是否还在这个区间之内呢?
这时候就要用到一个结构体了

struct node
{
    int val;
    int pos;
};

val存储该点的值,pos存储该点的位置,就是为了能够在循环中判断能否把这个点踢掉
根据单调队列的性质,如果我们想要将一个新的点插入
(你比如)
先看样例 当我们要在队列中插入第m + 1个元素的时候
也就是1
现在队列中是 7 8
他们分别对应的位置 1 2
因为要从队尾插入嘛
你想想你排队 如果有人一下子直接到队首,你是不是会很不爽,认为他没有资格
但是如果他一个一个插队,从队尾挨个上来,你不爽也没用的
所以单调队列也是队列,也是如此,没有元素有资格直接到头
你要慢慢来
这时候代码就很明显了

while((head <= tail)&&(v[tail].val >= a[i - 1]))
            tail--;
        v[++tail].val = a[i - 1];
   //这里i - 1要解释一下,因为该题0也要计算进去

那么对于已经过期的元素怎么办呢?
如果一个元素从队首开始t人
如果队首没有过期 其他的元素你管他干嘛?又不是答案,现在又用不到
如果队首过期,那就t掉他继续t下一个 直到找到一个没有过期的,然后参考上一步就OK了

while((head <= tail)&&(v[head].pos < i - m))
            head++;

接下里贴代码

手写版:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n,m;
inline int rd()
{
    int data = 0;
    int f = 1;
    char ch = getchar();
    while(ch < '0'||ch > '9')
    {
        if(ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0'&&ch <= '9')
    {
        data = (data<<3) + (data<<1) + ch - '0';
        ch = getchar();
    }
    return f * data; 
}
int a[2000010];
int min_que[2000010];
struct node
{
    int val;
    int pos;
}v[2000010];
void write(int x)
{
    if(x > 10)
        write(x/10);
    putchar(x%10 + '0');	
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 0;i < n;i++)
        a[i] = rd();
    int head = 1,tail = 0;
    min_que[0] = 0;
    for(int i = 1;i < n;i++)
    {
        while((head <= tail)&&(v[tail].val >= a[i - 1]))
            tail--;
        v[++tail].val = a[i - 1];
        v[tail].pos = i - 1;
        while((head <= tail)&&(v[head].pos < i - m))
            head++;
        min_que[i] = v[head].val;
    }
    for(int i = 0;i < n;i++)
        printf("%d\n",min_que[i]);
}

STL版:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<deque>
using namespace std;
const int maxsize = 2000010;
int n,m;
struct node
{
    int val;
    int pos;
}A[maxsize];
deque<node> min_Q;
inline int rd()
{
    int data = 0;
    int f = 1;
    char ch = getchar();
    while(ch < '0'||ch > '9')
    {
        if(ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0'&&ch <= '9')
    {
        data = (data<<3) + (data<<1) + ch - '0';
        ch = getchar();
    }
    return f * data; 
}
int min_que[maxsize]; 
int main()
{
    n = rd(),m = rd();
    for(int i = 1;i <= n;i++)
    {
        A[i].val = rd();
        A[i].pos = i - 1;
    }
    min_que[0] = 0;
    for(int i = 1;i < n;i++)
    {
        while(!min_Q.empty()&&min_Q.back().val >= A[i].val)
            min_Q.pop_back();
        min_Q.push_back(A[i]);
        while(!min_Q.empty()&&min_Q.front().pos < i - m)
            min_Q.pop_front();
        min_que[i] = min_Q.front().val;
    }
    for(int i = 0;i < n;i++)
        printf("%d\n",min_que[i]);	
            
}

小小用了一下快读,不懂的同学可以直接用scanf代替
不要用cin会超时(除非你把std同步关掉)
如果这道题你过了,就可以看一下以下两题,都差不多,难度不会太大,注意边界条件就可以过了
传送门: P1886滑动窗口P2032扫描

最后再介绍一下这个优先队列的作用,一般是用来优化DP,OI中较少直接仅仅考察该算法,同常都是和DP结合起来。

标签:ch,洛谷,val,P1440,min,int,while,007,include
From: https://www.cnblogs.com/zyihan-crz/p/18637894

相关文章

  • [COCI2006-2007#6] V
    前言赛时联想到了讲的一道题认为不可以使用数位\(\rm{dp}\),但是那道题实际上形式上跟这个题不同,所以其实是可以用的思路首先我们用数位\(\rm{dp}\)可以简单地解决选择数字的问题,套路的用\(f(1,r)-f(1,l-1)\)可以解决统计答案的问题,还需要具体的讨论转移怎......
  • LeetCode-整数反转(007)
    一.题目描述给你一个32位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。如果反转后整数超过32位的有符号整数的范围 [−231, 231 −1] ,就返回0。假设环境不允许存储64位整数(有符号或无符号)。二.示例 示例1:输入:x=123输出:321示例2:输入:x=-......
  • 洛谷 P8773 [蓝桥杯 2022 省 A] 选数异或 做题记录
    前置芝士:无?思路搜线段树的tag找到了一道非线段树题(因为\(\oplus\)是可逆的,即我们既可以\(a\oplusb=c\)同时也有\(a\oplusc=b\)。那么这启示我们,一个数\(a\)可以匹配的数一定为\(a\oplusx\)。我们用\(lst\)记录每一个元素最后出现的位置,设\(f_i\)为右......
  • 004. [NOIP2017 提高组] 机器翻译(洛谷P1540)
    004.[NOIP2017提高组]机器翻译(洛谷P1540)题目背景NOIP2010提高组T1题目描述小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章。这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换。对于每个英文单词,软件会先在内存中查......
  • 005. [NOIP2017 提高组] 时间复杂度(洛谷P3952)
    005.[NOIP2017提高组]时间复杂度(洛谷P3952)题目背景NOIP2017提高组D1T2题目描述小明正在学习一种新的编程语言A++,刚学会循环语句的他激动地写了好多程序并给出了他自己算出的时间复杂度,可他的编程老师实在不想一个一个检查小明的程序,于是你的机会来啦!下面请你编写程序......
  • 中考阅读理解深入逻辑分析-007 Hooves of Justice: The Equine Guardians 正义之蹄:马
    中考阅读理解深入逻辑分析-007HoovesofJustice:TheEquineGuardians正义之蹄:马匹守护者文章正文​PoliceofficerDenniswasrecentlypatrolling(巡逻)thestreetsofNewark,NewJersey.Suddenly,hefoundfourmenfighting.Asheapproached,oneofthemen......
  • gesp(二级)(15)洛谷:B4036:[GESP202409 二级] 数位之和
    gesp(二级)(15)洛谷:B4036:[GESP202409二级]数位之和题目描述小杨有nnn个正整数,他认为一个正整数是美丽数字当且仅当该正整数每一位数字的总和是......
  • gesp(二级)(16)洛谷:B4037:[GESP202409 二级] 小杨的 N 字矩阵
    gesp(二级)(16)洛谷:B4037:[GESP202409二级]小杨的N字矩阵题目描述小杨想要构造一个m×mm\timesmm×m......
  • 洛谷题单指南-线段树的进阶用法-P3834 【模板】可持久化线段树 2
    原题链接:https://www.luogu.com.cn/problem/P3834题意解读:静态区间第k小问题,可持久化线段树(也称为主席树)模版题。解题思路:一、朴素想法:如何求完整区间[1,n]第k小1、权值线段树设n个数构成序列a,b数组代表a中元素出现的次数,即b数组的构建方式为对每一个a[i]做b[a[i]]++。针对b......
  • 洛谷 P3293 [SCOI2016] 美味
    题目描述一家餐厅有\(n\)道菜,编号\(1,2,\ldots,n\),大家对第\(i\)道菜的评价值为\(a_i\)。有\(m\)位顾客,第\(i\)位顾客的期望值为\(b_i\),而他的偏好值为\(x_i\)。因此,第\(i\)位顾客认为第\(j\)道菜的美味度为\(b_i\oplus(a_j+x_i)\),\(\oplus\)表示异或运......