先分析一下单调队列的题,要不然都快忘光了。
题目大意:给你一串长度为n的数组,一扇长度为k的窗从最左端滑动到最右端,每次滑动如下表
求每次滑动的min.value 和 max.value.
输入格式
第 1 行 n,k, 第 2 行为长度为 n 的数组
输出格式
2 行, 第 1 行每个位置的 min value, 第 2 行每个位置的 max value
样例数据
input
8 3
1 3 -1 -3 5 3 6 7
output
-1 -3 -3 -3 3 3
3 3 5 5 6 7
数据规模与约定
20%: n<=500;
50%: n<=100000;
100%: n<=1000000;
时间限制:1s
空间限制:256MB
主要思路:控制窗户移动,选出每次移动的最小值,存入数列中,把比自己大或小的挤出队列(找大的挤小的,找小的挤大的),并且保证队首是我们要求的值,分两部分分别求最大最小。代码如下:
#include<bits/stdc++.h>
using namespace std;
int n,k,a[1000010],q[1000010],head=1,tail;
int main()
{
scanf("%d%d",&n,&k);//n个数,k长度的查询
for (int i=1;i<=n;++i)
scanf("%d",&a[i]);//读入n个数
for (int i=1;i<=n;++i)//先处理最小值
{
if (i-q[head]>=k) head++;//当超过k的时候,计算下一组m个数。 控制窗户移动
while (a[i]<a[q[tail]]&&head<=tail)//目的让最小的值留在队首。当元素小于队尾的数,队尾的数出栈,队尾指针减减。
tail--;
q[++tail]=i;//否则的话,当前元素进队,队尾指针加加
if (i>=k)
{
if (i==n) cout<<a[q[head]]<<endl;
else cout<<a[q[head]]<<" "; //输出队首元素,处理最后一个元素的输出。
}
}
memset(q,0,sizeof(q));
head=1;
tail=0;
for (int i=1;i<=n;++i)
{
if (i-q[head]>=k) head++;
while (a[i]>a[q[tail]]&&head<=tail)//同上,目的让最大的值留在队首。当元素大于队尾的数,队尾的数出栈,队尾指针减减。
tail--;
q[++tail]=i;
if (i>=k)
{
if (i==n) cout<<a[q[head]]<<endl;
else cout<<a[q[head]]<<" ";
}
}
return 0;
}
注:输出时空格的输出千万注意,否则等待你的将是0分~
另,附一图供大家一观:
(全是题目哦~)