洛谷:P1440 求m区间内的最小值(彻底掌握单调队列)

本文解析了如何使用单调队列优化算法解决计算机科学问题P1440,介绍了单调队列的工作原理、实现流程,并特别强调了处理大规模数据和输出效率的方法。关键步骤包括构建单调递增队列,去尾和删头操作,以及代码示例。
摘要由CSDN通过智能技术生成

一、题目

题目传送门:P1440 求m区间内的最小值 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1440

题目描述

62ad3f41c6ae45c9a6acd1ba0e10a824.png

二、题解

1.本题难点

        本题用暴力解法时间复杂度为O(n*m)

        所以我们就可以考虑用单调队列优化时间复杂度为O(n)

        下面我们来了解什么是单调队列:

单调队列,顾名思义,是一种具有单调性的队列。众所周知,单调性有单调递增和单调递减两种,相应的单调队列也分为单调递增队列和单调递减队列两种。

  • 单调递增队列:保证队列头元素一定是当前队列的最小值,用于维护区间的最小值。

  • 单调递减队列:保证队列头元素一定是当前队列的最大值,用于维护区间的最大值。

 实现流程:

实现单调队列,主要分为三个部分:

  • 去尾操作队尾元素出队列。当队列有新元素待入队,需要从队尾开始,删除影响队列单调性的元素,维护队列的单调性。(删除一个队尾元素后,就重新判断新的队尾元素)

去尾操作结束后,将该新元素入队列。

  • 删头操作队头元素出队列。判断队头元素是否在待求解的区间之内,如果不在,就将其删除。(这个很好理解呀,因为单调队列的队头元素就是待求解区间的极值)

  • 取解操作 :经过上面两个操作,取出 队列的头元素 ,就是 当前区间的极值

2.本题注意事项

1.数据量大的时候,用cout输出的时候千万别和endl一起,如果我们的算法思路一致,可能就是用了cout<<endl;而超时建议改用printf或用cout<<"\n";

具体原因你试试就知道,本题用cout<<endl输出就会超时,具体说明请前往传送门

传送门std::endl为什么导致程序变慢 – 胡超博客 (imhuchao.com)

 定义两个超大数组时改用全局变量,不然你的编译器可能运行出错

3.过程讲解

1)定义两个数组,一个数组q[n]用来作为一个简单队列,一个数组a[n]用来接收传进来的元素,记得将数组最大化,确保数据量大的时候全部能存取。q[n]队列里存的是数组的下标,访问元素可以用a[q[n]]来访为第n个元素。

2)因为第一元素的前没有前m项,所以直接输出0

3)写一个单调队列

4.代码

#include <iostream>
using namespace std;
int q[2000005], a[2000005];
int main()
{
	
	int m, k, front = 1, rear = 0;
	cin >> m >> k;

	for (int i = 1; i <= m; i++)
		cin >> a[i];
	cout << 0 << endl;
	for (int i = 1; i <= m - 1; i++) //构建单调队列
	{
	while (front <= rear &&q[front] <= i - k) //保证队首在前m区间内
			front++;
	while (front <= rear && a[q[rear]] >= a[i])//维护一个单调递增队列
			rear--;
		q[++rear] = i;   //入队
		cout<<a[q[front]]<<"\n"; 
	}
	return 0;
}

5.附上结果

d7f0ceb6fbbe44cba97be8b1477e4cd2.png

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值