[CF] 1307F Cow and Vacation(思維/貪心)
題目描述
有一個長為 n 的序列 a,以及一個大小為 k 的視窗。現在這個從左邊開始向右滑動,每次滑動一個單位,求出每次滑動後窗口中的最大值和最小值。
例如:
The array is [1,3,−1,−3,5,3,6,7] and k=3。
輸入格式
輸入一共有兩行,第一行有兩個正整數 n,k。 第二行 n個整數,表示序列 a
輸出格式
輸出共兩行,第一行為每次視窗滑動的最小值
第二行為每次視窗滑動的最大值
輸入輸出樣例
輸入 #18 3 1 3 -1 -3 5 3 6 7輸出 #1
-1 -3 -3 -3 3 3 3 3 5 5 6 7
心路歷程:
一開始覺得這個題非常簡單,看到是什麼單調佇列的模板,我心想,啥(⊙_⊙)?單調佇列?我咋沒發現單調?
一開始的想法是從先找到1~k內的最大值和最小值,然後從k+1開始訪問,如果當前值比最大值大或者比最大值小,那麼就更新這個值,並且把它複製到陣列中,最後直接輸出結果。
怎麼樣?思路非常清晰,步驟非常整潔,可惜就是過不去有樣例(汗-_-||)
為什麼呢?
注意:這裡是滑動視窗啊!!滑動!!一開始的最大值和最小值有可能被劃出去啊~~
所以上面這種方法肯定行不通,但是厚顏無恥的我還是把偶的非AC程式碼搬了上來:︿( ̄︶ ̄)︿
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll n,k; ll a[5020000]; ll maxn=-9999999999999,minn=9999999999999; ll minnn[5020000],maxnn[5020000]; int main() { cin>>n>>k; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=k;i++) { maxn=max(maxn,a[i]); minn=min(minn,a[i]); } maxnn[1]=maxn; minnn[1]=minn;int mi=1,ma=1; for(int i=k+1;i<=n;i++) { if(a[i]>=maxn) maxn=a[i]; ma++; maxnn[ma]=maxn; if(a[i]<=minn) minn=a[i]; mi++; minnn[mi]=minn; } for(int i=1;i<=mi;i++) cout<<minnn[i]<<" "; cout<<'\n'; for(int i=1;i<=ma;i++) cout<<maxnn[i]<<" "; return 0; }
解題思路 :
好了,Y(^o^)Y,我們來看一下正解到底是個啥東東
因為這個佇列是滑動的,而stl 裡面並沒有給我們提供滑動型別的佇列,所以我們這裡需要自己用陣列進行模擬
來想一下,假設我原來的陣列元素就是樣例裡的:
1 3 -1 -3 5 3 6 7
設定陣列q中儲存的是我們當前視窗中最大值的下標
這樣的話我們可以發現一個顯然的事實:
假設元素為x y z ,那麼對於視窗中的最大值來說,如果 y > x ,我們就可以直接把x扔掉啦!因為我們可以用到x的地方只在x之前,而在x之後,始終存在一個y>x ,所以不管怎麼樣視窗中的最大值一定不是x,那麼x還有什麼存在的必要嗎?沒有,所以我們可以直接把它從陣列q中刪除(從佇列中刪除)。而入如果x<y,那麼x還有可能是整個視窗中的最大值,所以我們儲存x。
另外一點需要注意的是,如果當前迴圈到的元素下標是i , 視窗長度是k ,那麼如果 i-k+1 的值(也就是視窗起點的下標)已經大於我們一開始的視窗下標(這裡用佇列頭元素來表示)了,那麼我們就必須把佇列頭元素彈出佇列,因為在實際操作中當前元素已經不再這個視窗中了,他已經劃出這個視窗了。
並且,按照這樣的方式,我們可以直接從頭更新佇列,而不需要像我一開始的錯解一樣需要從k+1開始遍歷,但是注意一下幾點:
1.如果按照我下面的程式碼來完成單調佇列的編寫,那麼一定要注意陣列從0開始存入,存到n-1
2.當我們遍歷到的元素下標已經大於k-1的時候就要開始輸出啦!!
3.元素頭指標初始下標(h)設定為0,尾指標初始下標設定成-1或者0都是可以的,對程式影響不大(反正都可以AC)
\(^o^)/~OK,到這,我們終於把所有東西都囉嗦完了(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤
AC程式碼如下:
#include<bits/stdc++.h> using namespace std; int n,k; int q[5020000],a[5020000]; int main() { cin>>n>>k; for(int i=0;i<n;i++) cin>>a[i]; int h=0,t=0; for(int i=0;i<n;i++) { while(h<=t&&a[i]<=a[q[t]]) t--; t++; q[t]=i; if(h<=t&&i-k+1>q[h]) h++; if(i>=k-1) cout<<a[q[h]]<<" "; } cout<<'\n'; h=0,t=0; for(int i=0;i<n;i++) { while(h<=t&&a[i]>=a[q[t]]) t--; t++; q[t]=i; if(h<=t&&i-k+1>q[h]) h++; if(i>=k-1) cout<<a[q[h]]<<" "; } return 0; }
----------------------end-----------------------