赞
踩
简要题意:
给定一个数组,求所有连续 m m m 个数的最大值和最小值。
首先,对于这种题目,用 5 + 5+ 5+ 种方法(至少),这里介绍几种吧。
根据 RMQ \texttt{RMQ} RMQ 算法解决问题。
用 f i , j f_{i,j} fi,j 表示从 i i i 开始往后 2 j 2^j 2j 个的最大值。( 2 j > n 2^j > n 2j>n 则视为 n n n)
那么,显然有:
f
i
,
j
=
{
a
i
,
j
=
0
f
f
i
,
j
−
1
,
j
−
1
,
j
≠
0
f_{i,j} =
其中, f i , j − 1 f_{i,j-1} fi,j−1 即往后先走 2 j − 1 2^{j-1} 2j−1 个, 再走 2 j − 1 2^{j-1} 2j−1 个,类似于 倍增 算法。
然后,预处理 log \log log,即可 O ( n log n ) O(n \log n) O(nlogn) 初始化, O ( 1 ) O(1) O(1) 回答。
时间复杂度: O ( n log n + k ) O(n \log n + k) O(nlogn+k).
期望得分: 50 p t s 50pts 50pts ~ 100 p t s 100pts 100pts.(取决于程序常数,听说这道题目 卡任何带 log \log log 的算法,不知道能不能卡过去)
分块,本题效率最慢的算法。
显然,分成 n \sqrt{n} n 块,对每块分别计算,对于 n − k + 1 n-k+1 n−k+1 个块分别询问。
时间复杂度: O ( ( n − k + 1 ) n ) O((n-k+1) \sqrt{n}) O((n−k+1)n ), 如果是极限数据 n = 1 0 6 n=10^6 n=106, k = 1 k=1 k=1 就直接卡掉了。( k k k 很小就可以)
期望得分: 50 p t s 50pts 50pts ~ 100 p t s 100pts 100pts.
实际得分: 92 p t s 92pts 92pts.(有人实测过,卡常得高分)
线段树,在分块与 RMQ \text{RMQ} RMQ 之间。
这题的算法上有线段树但是过不了。。。
不用说了吧,模板在此.
时间复杂度: O ( n log n + k log n ) O(n \log n + k \log n) O(nlogn+klogn). (显然被卡超时,不过:)
期望得分: 50 p t s 50pts 50pts ~ 100 p t s 100pts 100pts.
实际得分: 92 p t s 92pts 92pts.(真·卡常大法好)
指令集。???
学习完之后,相信你能随便用一个数据结构(甚至是暴力???)切掉本题!
时间复杂度: O ( n 2 ) O(n^2) O(n2) ~ O ( n log n + k log n ) O(n \log n + k \log n) O(nlogn+klogn) ~ O ( n log n + k ) O(n \log n + k) O(nlogn+k).
期望得分: 100 p t s 100pts 100pts.
实际得分: 92 p t s 92pts 92pts ~ 100 p t s 100pts 100pts.(众所周知数据加强过一次,要是加强之前交没准就过了,不然没准被卡)
扯了这么多。。终于到正题了!
单调队列 为什么叫这么名字,它不是白叫的好吧 像平衡树要是不平衡那要它干么呢 。
假设,现在一个君王他叫做 C C F CCF CCF( C C F = Centre Code Forces CCF = \text{Centre Code Forces} CCF=Centre Code Forces),有 8 8 8 名选手,她们(对,就是她)的才华值分别为:
1 3 -1 -3 5 3 6 7
她们从左往右依次是:zhk
,yy
,kkk
,bfw
,gyx
,cz
,wxq
,rxz
.
然后,他们参加 C C F CCF CCF 比赛的年龄分别为 8 8 8 ~ 1 1 1 岁。(嗯?没错)
C C F CCF CCF 有一个 怪癖:只要一个选手参加 C C F CCF CCF 比赛超过 3 3 3 年,她(?)就觉得该选手没有潜力了。
zhk
在
8
8
8 岁的时候进入了,他发现没有一个人比他更厉害,所以他留下来了。
yy
在
7
7
7 岁的时候也进入了
C
C
F
CCF
CCF 比赛,并把 zhk
踢下去,因为
3
>
1
3>1
3>1. zhk
想:他比我小还比我强,我退役吧,然后就退役了。
kkk
在
6
6
6 岁时一来,发现被 yy
吊打了(
3
>
−
1
3 > -1
3>−1),但是他想:你比我强,但是我比你小,我更有潜力,我活的比你久,没准等你退役我就是老大! 于是留了下来。然后,
CCF Round 1
\text{CCF Round 1}
CCF Round 1 冠军产生:yy
.
bfw
一看:嗯?怎么前面的人都比我强啊?事实 然后他觉得,自己留下来的时间更久,等她们都退役再说。 于是留了下来。
CCF Round 2
\text{CCF Round 2}
CCF Round 2 冠军产生:yy
.
gyx
来了之后,他发现自己是最强的
5
>
3
5>3
5>3,然后所有的人(除了她)都觉得 有人比我小还比我强,集体退役。yy
又遭到
C
C
F
CCF
CCF 的潜力质疑,精神病发作了。
CCF Round 3
\text{CCF Round 3}
CCF Round 3 冠军产生:gyx
.
cz
来了之后,嗯发现自己是最弱的,但是她想: CCF质疑 gyx
比我前,所以我比她活得长!活得长就是报仇,所以要留下来!
CCF Round 4
\text{CCF Round 4}
CCF Round 4 冠军产生:gyx
.
wxq
一到,瞬间 吊打集训队,吊打全场然后 gyx
和 cz
一起退役了。
CCF Round 5
\text{CCF Round 5}
CCF Round 5 冠军产生:wxq
.
最后 rxz
到了,结束了 wxq
的
C
C
F
CCF
CCF 生涯,把她弄自闭然后滚出集训队了。(我才不会告诉你 )
CCF Round 6
\text{CCF Round 6}
CCF Round 6 冠军产生:rxz
就是
C
C
F
CCF
CCF 出题人rxz
.
若干年过去了, CCF \text{CCF} CCF 决定:分数越低的人得奖越高,那些强者实在弱不下来,于是又开始了第二场 互逼退役 的旅程。。
综上可见,单调队列的过程本质就是一个维护队列的过程,参加 C C F CCF CCF 则入队,退役则出队。
显然,如果用系统的
queue
\text{queue}
queue 写会多出一个
log
\log
log,然后变成
O
(
n
log
n
)
O(n \log n)
O(nlogn) 级别,沦为和上述数据结构一样的。(智商不够,数据结构来凑)
所以今天我们用 手写队列,用 l , r l,r l,r 指针维护当前在队列中的元素。
时间复杂度: O ( n + k ) O(n + k ) O(n+k).
实际得分: 100 p t s 100pts 100pts.
#pragma GCC optimize(2) #include<bits/stdc++.h> using namespace std; const int N=1e6+1; inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();} int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;} int n,m,a[N]; int q[N],p[N]; //q[i] 记录数值 , p[i] 记录编号 int main(){ n=read(),m=read(); for(int i=1;i<=n;i++) a[i]=read(); // for(int i=1;i<=n;i++) printf("%d ",a[i]); puts(""); int l=1,r=0; for(int i=1;i<=n;i++) { while(l<=r && q[r]>=a[i]) r--; //新来的人先吊打掉一波 q[++r]=a[i]; p[r]=i; while(p[l]<=i-m) l++; //被质疑的可以直接退役 // printf("%d %d\n",l,r); if(i>=m) printf("%d ",q[l]); } puts(""); l=1;r=0; for(int i=1;i<=n;i++) { while(l<=r && q[r]<=a[i]) r--; q[++r]=a[i]; p[r]=i; while(p[l]<=i-m) l++; if(i>=m) printf("%d ",q[l]); } //这边同理 return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。