有一个长为 nn 的序列 aa,以及一个大小为 kk 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。
例如:
The array is [ 1 , 3 , − 1 , − 3 , 5 , 3 , 6 , 7 ] , a n d [1,3,-1,-3,5,3,6,7], and [1,3,−1,−3,5,3,6,7],and k = 3 k = 3 k=3。
输入一共有两行,第一行有两个正整数 n,k。 第二行 n 个整数,表示序列 a
输出共两行,第一行为每次窗口滑动的最小值
第二行为每次窗口滑动的最大值
输入
8 3
1 3 -1 -3 5 3 6 7
输出
-1 -3 -3 -3 3 3
3 3 5 5 6 7
【数据范围】
对于 50% 的数据,1≤n≤105 ;
对于 100% 的数据,1≤k≤n≤106 ,ai ∈[−231,231)
单调队列模板题,单调递增和递减。
一开始的手打队列代码看起来恨复杂,后来写题解看不下去 改进成queue。下面两种都有。
#include
#include
#include
#define M 1001000
#define p(a) putchar(a+'0')
#define pin ch=getchar()
using namespace std;
int headu=1,headd=1,tailu=1,taild=1,k,n,u[M],d[M],a[M],mx[M],udel[M],ddel[M];
inline int read() //快读
{
register int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')w=-1;
pin;
}
while(ch>='0'&&ch<='9')
{
s=(s<<1)+(s<<3)+(ch^48);
pin;
}
return s*w;
}
inline void write(register int x) //快输
{
if(x<0)
{
p(-3);
x=~(x-1);
}
int s[20],top=0;
while(x)
{
s[++top]=x%10;
x/=10;
}
if(!top) s[++top]=0;
while(top) p(s[top--]);
p(-16);
}
void in() //输入部分
{
n=read();
k=read();
for(register int i=1; i<=n; i++)
a[i]=read();
if(k==1)
{
for(register int i=1; i<=n; i++) write(a[i]);
printf("\n");
for(register int i=1; i<=n; i++) write(a[i]);
exit(0);
}
return;
}
void up(register int x,register int i) //单调递增
{
for(; tailu>=headu&&u[tailu]>x; tailu--);
u[++tailu]=x;
udel[tailu]=i;
if(i>=k)
{
while((i-k+1)>udel[headu]) headu++;
}
return;
}
void down(register int x,register int i) //单调递减
{
for(; taild>=headd&&d[taild]<x; taild--);
d[++taild]=x;
ddel[taild]=i;
if(i>=k)
{
while((i-k+1)>ddel[headd]) headd++;
}
return;
}
int main()
{
in();
u[1]=d[1]=a[1];
udel[1]=ddel[1]=1;
for(register int i=2; i<=n; i++)
{
up(a[i],i);
down(a[i],i);
if(i<k) continue;
write(u[headu]);
mx[i]=d[headd];
}
p(-38);
for(register int i=k; i<=n; i++) write(mx[i]);
return 0;
}
#include
#include
#include
using namespace std;
long long n,k,a[3000001];
deque<long long> up,down;
inline int read() //快读
{
register int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
s=(s<<1)+(s<<3)+(ch^48);
ch=getchar();
}
return s*w;
}
inline void write(register int x) //快输
{
if(x<0)
{
putchar('-');
x=~(x-1);
}
int s[20],top=0;
while(x)
{
s[++top]=x%10;
x/=10;
}
if(!top) s[++top]=0;
while(top) putchar(s[top--]+'0');
}
int main()
{
n=read();k=read();
for(int i=1; i<=n; i++) //单调递增求最小
{
a[i]=read();
while(!up.empty()&&up.front()<=(i-k)) up.pop_front(); //弹出“过时”的即不在窗口里的元素
while(!up.empty()&&a[up.back()]>a[i]) up.pop_back(); //弹出比a[i]大的元素,维护单调递增
up.push_back(i); //将该元素下标推入up队列
if(i>=k) write(a[up.front()]),putchar(' ');
}
cout<<endl;
for(int i=1; i<=n; i++) //单调递减求最大
{
while(!down.empty()&&down.front()<=(i-k)) down.pop_front(); //弹出“过时”的元素
while(!down.empty()&&a[down.back()]<a[i]) down.pop_back(); //维护单调递减
down.push_back(i); //将该元素下标推入down队列
if(i>=k) write(a[down.front()]),putchar(' ');
}
}
不加快读快输会超时TTTTT