POJ 2328 (单调队列)
题目输出一个n,一个k,分别代表n个数,长度为k的框,求狂每移动一次,框里面的最大值最小值
样例
8 3 1 3 -1 -3 5 3 6 7
-
1 3 -1
-
3 -1 -3
-
-1 -3 5
-
-3 5 3
-
5 3 6
-
3 6 7
最小
-1 -3 -3 -3 3 3
最大
3 3 5 5 6 7
暴力复杂度高,这里用单调队列
最小值 (单调递增的队列)
1 这个队列可以可以尾巴和头都去数。
2 当尾巴的数大于要存进来的数时候,尾巴弹出
3 当队列头的数和尾巴的数之间的距离大于等于k,头的数弹出
(这题cin cout可能会超时)
每次队列中的数字是这样变化的
- 1
- 1 3 //3大于1,存入
- -1 //-1小于3,3弹出。 -1小于1,1弹出
- -3
- -3 5
- -3 3
- 3 6 //-3 与 6 的距离大于k-1,-3弹出
- 3 6 7
输出 队列头 就行
最大值 是单调递增区别不大
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <string> #include <map> #include <iomanip> #include <algorithm> #include <queue> #include <stack> #include <set> #include <vector> #define ll long long ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} ll lcm(ll a,ll b){return a/gcd(a,b)*b;} #define MAX INT_MAX #define FOR(i,a,b) for( int i = a;i <= b;++i) #define bug cout<<"--------------"<<endl using namespace std; struct node //模拟的队列,place记录下标,nub记录数 { int place,nub; }que[1100000]; int v[1100000]; int n,k; void findmin() { memset(que,0,sizeof(que)); int head=1,tail=0; for(int i=1;i<=k-1;++i) // 先把前k-1个数预处理进去队列中 { while(que[tail].nub>=v[i] && tail>=head) { tail--; } tail++; que[tail].nub=v[i]; que[tail].place=i; } for(int i=k;i<=n;++i) { while(que[tail].nub>=v[i] && tail>=head) { tail--; } tail++; que[tail].nub=v[i]; que[tail].place=i; while(que[tail].place-que[head].place>=k) { head++; } printf("%d ",que[head].nub); } } void findmax() { memset(que,0,sizeof(que)); int head=1,tail=0; for(int i=1;i<=k-1;++i) { while(que[tail].nub<=v[i] && tail>=head) { tail--; } tail++; que[tail].nub=v[i]; que[tail].place=i; } for(int i=k;i<=n;++i) { while(que[tail].nub<=v[i] && tail>=head) { tail--; } tail++; que[tail].nub=v[i]; que[tail].place=i; while(que[tail].place-que[head].place>=k) { head++; } printf("%d ",que[head].nub); } } int main() { cin>>n>>k; FOR(i,1,n) { cin>>v[i]; } findmin(); printf("\n"); findmax(); }