sliding windows (poj 2823) 题解
2016-01-10 18:40
246 查看
【问题描述】
给你一个长度为N的数组,一个长为K的滑动的窗体从最左移至最右端,你只能见到窗口的K个数,每次窗体向右移动一位,如下表:
1 3 -1 -3 5 3 6 7
3 3 5 5 6 7
我们取前k个数中的最大值和最小值,放入两个队列中,设放最大值的为k,放最小值的为q,对于之后的每一个数如果比k中的队尾元素大,那么k的队尾元素便可删去(因为可以证明,在之后的任何一个区间内都用不上该元素),若比队尾元素小,便入队。q队列则是反操作。于是,对于每一个区间的最小值和最大值,我们只需要记录q和k队列中的队首元素即可。由于输出的要求我在这用了两个过程,先求最小值,然后求最大值。详见代码。
给你一个长度为N的数组,一个长为K的滑动的窗体从最左移至最右端,你只能见到窗口的K个数,每次窗体向右移动一位,如下表:
【样例输入】
8 31 3 -1 -3 5 3 6 7
【样例输出】
-1 -3 -3 -3 3 33 3 5 5 6 7
【解题思路】
首先,不难想到用枚举的办法,对于每一个区间,枚举其中的最大值和最小值,但对于n<=1000000的数据来说,枚举必定超时,因此我们可以用到队列来进行优化。我们取前k个数中的最大值和最小值,放入两个队列中,设放最大值的为k,放最小值的为q,对于之后的每一个数如果比k中的队尾元素大,那么k的队尾元素便可删去(因为可以证明,在之后的任何一个区间内都用不上该元素),若比队尾元素小,便入队。q队列则是反操作。于是,对于每一个区间的最小值和最大值,我们只需要记录q和k队列中的队首元素即可。由于输出的要求我在这用了两个过程,先求最小值,然后求最大值。详见代码。
【代码实现】
var q,a:array[1..1000000] of longint; n,k,i,j:longint; procedure work; var i,f,r:longint; begin f:=1; r:=1; q[f]:=1; for i:=2 to k do begin while (f<=r)and(a[q[r]]>=a[i]) do dec(r); inc(r); q[r]:=i; end;//初始化q队列 write(a[q[f]],' '); for i:=2 to n-k+1 do begin if q[f]<i then inc(f); while (f<=r)and(a[q[r]]>=a[i+k-1]) do//若当前元素比队尾元素小,删除队尾元素 dec(r); inc(r); q[r]:=i+k-1; write(a[q[f]],' '); end; end; procedure work1; var i,f,r:longint; begin f:=1; r:=1; q[f]:=1; for i:=2 to k do begin while(f<=r)and(a[q[r]]<=a[i]) do dec(r); inc(r); q[r]:=i; end; write(a[q[f]],' ');//初始化k队列 for i:=2 to n-k+1 do begin if q[f]<i then inc(f); while (f<=r)and(a[q[r]]<=a[i+k-1]) do//若当前数比队尾元素大,删除队尾元素 dec(r); inc(r); q[r]:=i+k-1; write(a[q[f]],' '); end; end; begin readln(n,k); for i:=1 to n do read(a[i]); work; fillchar(q,sizeof(q),0); writeln; work1; writeln; end.
相关文章推荐
- 集合删数 (vijos 1545) 题解
- 合并果子 (codevs 1063) 题解
- 等价表达式 (codevs 1107)题解
- 生理周期 (poj 1006) 题解
- 区间 (vijos 1439) 题解
- 区间覆盖问题 题解
- 种树 (codevs 1653) 题解
- 雷达装置 (POJ 1328/ codevs 2625)题解
- 棋盘覆盖问题 题解
- 奇怪的函数 (codevs 3538/1696) 题解
- 计算系数 (codevs 1137) 题解
- 一元三次方程 (codevs 1038)题解
- 乌龟棋 (codevs 1068)题解
- 2016.01.08-2016.01.09回顾
- 全排列 (codevs 1294)题解
- 编码问题 题解
- final个人阅读作业
- Linux用户组与用户组进阶命令
- TOM猫
- java写一个死锁