【题目大意】
给你一个长度不超过1e6的序列,现在有一个数字k,表示长度为k的子序列自左到右滑动时保持长度为k。
现在要求出该长度为k区间在滑动的过程中区间的最大值最小值。
【解题思路】
如果此题直接模拟或者利用最大值的单调性来做的话,在长度为k的区间上无法保证次大值的正确性。
本题的正确的思路是单调队列。
首先求出每次滑动的最小值。
我们考虑维护一个下标队列,首先将前k的数直接加入队列。
然后用一个指针从k+1位扫到最后一位,遇到的数如果比要插入的数大,则删除队尾元素,将指针前移,重复操作知道该元素遇到一个比它大的元素,或队列为空。
记住保存到一定是下标。
然后重复以上操作求出最大值(将条件改为“遇到的数如果比要插入的数小”)
【代码】
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cctype>
#include<iomanip>
#define LL long long
//#define LOCAL
using namespace std;
namespace output{
char ch[1000];
}
const int N=1000011;
int n,m,k;
int head,tail;
int q[N];
int a[N];
inline int CIN(){
int num=0;
int f=1;
char c=getchar();
while ((c>'9'||c<'0')&&c!='-') c=getchar();
if (c=='-'){
f=-1;
c=getchar();
}
while (c>='0'&&c<='9'){
num=(num<<3)+(num<<1)+c-'0';
c=getchar();
}
return f*num;
}
inline void COUT(int x){
if (x==0){
putchar(48);
return;
}
if (x<0){
putchar('-');
x=-x;
}
char *s=output::ch;
while (x){
*(++s)=x%10;
x/=10;
}
while (s!=output::ch) putchar((*(s--))+48);
}
struct humdrum{//下标队列
int q[N];
bool exist[N];
int zjl;
void Insert_Max(int x){
while (tail>=head&&a[q[tail]]<=a[x]) exist[q[tail--]]=false;
q[++tail]=x;
exist[x]=true;
}
void Insert_Min(int x){
while (tail>=head&&a[q[tail]]>=a[x]) exist[q[tail--]]=false;
q[++tail]=x;
exist[x]=true;
}
void Delete(int x){
if (exist[x]) head++;
}
void Clear(){
memset(exist,false,sizeof(exist));
memset(q,0,sizeof(q));
zjl=0;
}
}que;
int main(){
#ifdef LOCAL
freopen("POJ2823.in","r",stdin);
#endif
while (scanf("%d%d",&n,&k)!=EOF){
que.Clear();
head=0;
tail=-1;
for (int i=1;i<=n;++i) a[i]=CIN();
for (int i=1;i<=k;++i) que.Insert_Min(i);
COUT(a[que.q[head]]);
putchar(' ');
for (int i=k+1;i<=n;++i){
que.Insert_Min(i);
que.Delete(i-k);
if (i!=n) COUT(a[que.q[head]]),putchar(' ');
else COUT(a[que.q[head]]),putchar('\n');
}
que.Clear();
head=0;
tail=-1;
for (int i=1;i<=k;++i) que.Insert_Max(i);
COUT(a[que.q[head]]);
putchar(' ');
for (int i=k+1;i<=n;++i){
que.Insert_Max(i);
que.Delete(i-k);
if (i!=n) COUT(a[que.q[head]]),putchar(' ');
else COUT(a[que.q[head]]),putchar('\n');
}
}
return 0;
}
【总结】
单调队列,单调栈可以优化很多问题,务必掌握!