寒假集训——单调队列(滑动窗口)、单调栈

小记:今天又起晚了,睁眼就八点了,真舒服啊。到了教室学长刚开始讲课,我到的时

间刚刚好还能签上到,miao。

今天的内容栈、队列和单调队列单调栈。之前早接触过这些内容,队列了解少一些,但

是单调栈之前理解了好久,理论理解完了又去理解代码,相当的耗时间。虽然再次听之

前的内容也忘了不少,但好歹轻松了一些,不想一开始学的时候呢么吓人了。

今天讲解了几个板子,通过听课和模板代码,对这部分内容了解更多了一些。


OK,接下来该写笔记了。

C++ STL简介及数据结构常用代码模板

队列和栈都可以通过数组模拟,但是c++有直接封装好的stl容器,肯定更方便。

\(stack\)\(deque\)\(queue\)分别是栈、双端队列、队列。

特别篇 P1443 马的遍历

其实这是一道bfs的题目但是用到了队列,由于对于bfs队列的过程还是不够熟悉,bfs

学习之后学的队列,使我在这个题中遇到了很大的阻碍(计数),因此特别记录下来

警醒自己,不能只记住板子,代码的流程应该熟悉,不能自以为正确,这个题就是自

以为正确而出现的问题。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 5e6 + 10;
const int M = 10100;
int maxx = -1e18;
int minn = 1e18;
int a[M][M];
int dx[8] = {-2, -2, 2, 2, 1, 1, -1, -1};
int dy[8] = {1, -1, 1, -1, 2, -2, 2, -2};
int n, m, x, y, cnt, nx, ny;
bool f[M][M];
//pair<int, int>r[M];
queue<pair<int, int>> q;
int k = -1;
void bfs()
{
	q.push({x, y});
	f[x][y] = 1;
	while (!q.empty())
	{
		int i, j;
		auto t = q.front();
		q.pop();
		for (i = 0; i < 8; i++)
		{
			int xx = t.first + dx[i];
			int yy = t.second + dy[i];
			if (xx > 0 && yy > 0 && xx <= n && yy <= m && f[xx][yy] == 0)
			{
				f[xx][yy] = 1;
				a[xx][yy] = a[t.first][t.second] + 1;//关键错误点
				q.push({xx, yy});
			}
		}
	}
}
signed main()
{
	cin >> n >> m >> x >> y;
	int i, j;
	bfs();
	for (i = 1; i <= n; i++)
	{
		for (j = 1; j <= m; j++)
		{
			if (a[i][j] == 0)
			{
				if (i != x || j != y)
					printf("%-5d ", k);
				else
					printf("%-5d ", nx);
			}
			else
				printf("%-5d ", a[i][j]);
		}
		cout << endl;
	}
	return 0;
}

P5788 【模板】单调栈

#include<bits/stdc++.h> 
using namespace std;    
#define int long long      
#define endl '\n'          
const int N = 5e6 + 100;    
const int M = 10100;         
int cnt, sum;               
int a[N];                       
stack<int>st;                     // 定义一个整数栈st  
int s[N];                       
signed main()                  
{
	int n, i;                       // 定义两个整数变量n和i,n表示数组的长度,i是循环变量
	cin >> n;                      // 从标准输入读取n的值,即数组的长度
	for (i = 1; i <= n; i++)        // 循环读取数组的元素
	{
		cin >> a[i];                    // 从标准输入读取一个整数并存入数组a的第i个位置
	}
	for (i = 1; i <= n; i++)        // 循环处理数组中的每个元素
	{
		while (!st.empty() && a[i] > a[st.top()]) // 如果栈不为空且当前元素大于栈顶元素
		{
			s[st.top()] = i;                 // 将栈顶元素的插入位置存储到数组s中
			st.pop();                       // 弹出栈顶元素
		}
		st.push(i);                      // 将当前元素的索引i压入栈中
	}
	for (i = 1; i <= n; i++)        // 输出每个元素的插入位置
		cout << s[i] << " ";            // 在每个位置后面加一个空格并换行
}

P1886 滑动窗口 /【模板】单调队列

#include<bits/stdc++.h>  // 包含大部分的C++标准库  
using namespace std;    // 使用标准命名空间  
#define int long long      // 定义int为long long类型,增加整数范围  
#define endl '\n'           // 定义endl为换行符  
const int N = 5e6 + 100;    // 定义常量N,表示数组的最大长度  
const int M = 10100;        // 定义常量M,但在这段代码中没有使用  
int cnt, sum;               // 定义两个全局整数变量,但在这段代码中没有使用  
int a[N];                     // 定义一个长度为N的整数数组  
deque<int> q;                 // 定义一个整数双端队列q  
  
signed main() {             // 主函数,返回类型为signed,通常主函数返回类型为int  
    int n, k;                 // 定义两个整数变量n和k,分别表示数组的长度和窗口大小  
    cin >> n >> k;            // 从标准输入读取n和k的值  
    int i;                    // 定义一个循环变量i  
    for (i = 1; i <= n; i++)   // 循环读取数组的元素  
        scanf("%lld", &a[i]); // 从标准输入读取一个长整型数并存入数组a的第i个位置  
  
    // 第一部分:升序排序窗口输出顶部元素  
    for (i = 1; i <= n; i++) {  
        if (!q.empty() && i - q.front() + 1 > k)  // 如果队列不为空且当前位置与队列头部位置之差大于k  
            q.pop_front();                        // 则移除队列头部的元素  
        while (q.size() && a[i] <= a[q.back()])     // 如果队列非空且当前元素小于等于队列尾部元素  
            q.pop_back();                          // 则移除队列尾部的元素  
        q.push_back(i);                              // 将当前位置i加入队列尾部  
        if (i >= k)                                   // 如果当前位置大于等于k  
            cout << a[q.front()] << " ";             // 则输出队列头部的元素并后面加一个空格  
    }  
    cout << endl;                                      // 输出一个换行符  
    q.clear();                                           // 清空队列  
  
    // 第二部分:降序排序窗口输出顶部元素  
    for (i = 1; i <= n; i++) {  
        if (!q.empty() && i - q.front() + 1 > k)  // 如果队列不为空且当前位置与队列头部位置之差大于k  
            q.pop_front();                        // 则移除队列头部的元素  
        while (q.size() && a[i] >= a[q.back()])     // 如果队列非空且当前元素大于等于队列尾部元素  
            q.pop_back();                          // 则移除队列尾部的元素  
        q.push_back(i);                              // 将当前位置i加入队列尾部  
        if (i >= k)                                   // 如果当前位置大于等于k  
            cout << a[q.front()] << " ";             // 则输出队列头部的元素并后面加一个空格  
    }  
    cout << endl;                                      // 输出一个换行符  
}

P1739 表达式括号匹配

这段代码是一个\(C++\)程序,用于检查给定的字符串是否只包含有效的括号。

首先,程序通过 \(cin >> s\); 从标准输入读取一个字符串 \(s\)

然后,使用一个循环将字符串 \(s\) 的所有字符(除了最后一个字符)推入一个栈 \(st\)

之后,程序进入一个循环,该循环将栈中的每个字符逐个弹出并检查:

如果弹出的字符是 $ ) $,则 \(p\) 值增加1,表示已经遇到一个右括号。

如果弹出的字符是 \((\) ,则 \(p\) 值减少1,表示需要找到一个相应的左括号。

如果 \(p\) 的值变为负数,这意味着遇到了一个没有相应左括号的右括号,因此输出

\(NO\) 并结束程序。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 5e6 + 100;
const int M = 10100;
int cnt, sum;
string s;
stack<int> st;
signed main() {
	cin >> s;
	int i;
	for (i = 0; i < s.size() - 1; i++) {
		st.push(s[i]);
	}
	int p = 0;
	while (!st.empty()) {
		auto t = st.top();
		st.pop();
		if (t == ')') {
			p++;
		} else if (t == '(') {
			p--;
		}
		if (p < 0) {
			cout << "NO" << endl;
			return 0;
		}
	}
	if (p != 0) {
		cout << "NO" << endl;
		return 0;
	}
	cout << "YES" << endl;
}

P1440 求m区间内的最小值

滑动窗口

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 5e6 + 100;
const int M = 10100;
int cnt, sum;
deque<int> q;
int a[N];
signed main()
{
	int n, m;
	int i, j;
	cin >> n >> m;
	for (i = 1; i <= n; i++)
	{
		scanf("%lld", &a[i]);
	}
//	q.push_front(0);
	cout << 0 << endl;
	for (i = 1; i < n; i++)
	{
		if (!q.empty() && i - q.front() + 1 > m)
			q.pop_front();
		while (q.size() && a[i] <= a[q.back()])
			q.pop_back();
		q.push_back(i);
//		if (i >= m)
		cout << a[q.front()] << endl;
	}
}
/*
6 3
7 8 1 4 3 2
00 07 78 81 14 43
不必多言
*/
posted @ 2024-07-05 17:39  ZhangDT  阅读(9)  评论(0)    收藏  举报