簡要題意:
給定一個數組,求所有連續 個數的最大值和最小值。
首先,對於這種題目,用 種方法(至少),這裏介紹幾種吧。
算法一
根據 算法解決問題。
用 表示從 開始往後 個的最大值。( 則視爲 )
那麼,顯然有:
其中, 即往後先走 個, 再走 個,類似於 倍增 算法。
然後,預處理 ,即可 初始化, 回答。
時間複雜度:.
期望得分: ~ .(取決於程序常數,聽說這道題目 卡任何帶 的算法,不知道能不能卡過去)
算法二
分塊,本題效率最慢的算法。
顯然,分成 塊,對每塊分別計算,對於 個塊分別詢問。
時間複雜度:, 如果是極限數據 , 就直接卡掉了。( 很小就可以)
期望得分: ~ .
實際得分:.(有人實測過,卡常得高分)
算法三
線段樹,在分塊與 之間。
這題的算法上有線段樹但是過不了。。。
不用說了吧,模板在此.
時間複雜度:. (顯然被卡超時,不過:)
期望得分: ~ .
實際得分:.(真·卡常大法好)
算法四
指令集。???
學習完之後,相信你能隨便用一個數據結構(甚至是暴力???)切掉本題!
時間複雜度: ~ ~ .
期望得分:.
實際得分: ~ .(衆所周知數據加強過一次,要是加強之前交沒準就過了,不然沒準被卡)
算法五
扯了這麼多。。終於到正題了!
單調隊列 爲什麼叫這麼名字,它不是白叫的好吧 像平衡樹要是不平衡那要它幹麼呢 。
假設,現在一個君王他叫做 (),有 名選手,她們(對,就是她)的才華值分別爲:
1 3 -1 -3 5 3 6 7
她們從左往右依次是:zhk
,yy
,kkk
,bfw
,gyx
,cz
,wxq
,rxz
.
然後,他們參加 比賽的年齡分別爲 ~ 歲。(嗯?沒錯)
有一個 怪癖:只要一個選手參加 比賽超過 年,她(?)就覺得該選手沒有潛力了。
-
zhk
在 歲的時候進入了,他發現沒有一個人比他更厲害,所以他留下來了。 -
yy
在 歲的時候也進入了 比賽,並把zhk
踢下去,因爲 .zhk
想:他比我小還比我強,我退役吧,然後就退役了。 -
kkk
在 歲時一來,發現被yy
吊打了(),但是他想:你比我強,但是我比你小,我更有潛力,我活的比你久,沒準等你退役我就是老大! 於是留了下來。然後, 冠軍產生:yy
. -
bfw
一看:嗯?怎麼前面的人都比我強啊?事實然後他覺得,自己留下來的時間更久,等她們都退役再說。 於是留了下來。 冠軍產生:yy
. -
gyx
來了之後,他發現自己是最強的 ,然後所有的人(除了她)都覺得 有人比我小還比我強,集體退役。yy
又遭到 的潛力質疑,精神病發作了。 冠軍產生:gyx
. -
cz
來了之後,嗯發現自己是最弱的,但是她想: CCF質疑gyx
比我前,所以我比她活得長!活得長就是報仇,所以要留下來! 冠軍產生:gyx
. -
wxq
一到,瞬間 吊打集訓隊,吊打全場然後gyx
和cz
一起退役了。 冠軍產生:wxq
. -
最後
rxz
到了,結束了wxq
的 生涯,把她弄自閉然後滾出集訓隊了。(我纔不會告訴你) 冠軍產生:rxz
就是 出題人rxz
.
若干年過去了, 決定:分數越低的人得獎越高,那些強者實在弱不下來,於是又開始了第二場 互逼退役 的旅程。。
綜上可見,單調隊列的過程本質就是一個維護隊列的過程,參加 則入隊,退役則出隊。
顯然,如果用系統的 寫會多出一個 ,然後變成 級別,淪爲和上述數據結構一樣的。(智商不夠,數據結構來湊)
所以今天我們用 手寫隊列,用 指針維護當前在隊列中的元素。
時間複雜度:.
實際得分:.
#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;
}