1. 程式人生 > 實用技巧 >[CF] 1307F Cow and Vacation(思維/貪心)

[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

輸出格式

輸出共兩行,第一行為每次視窗滑動的最小值
第二行為每次視窗滑動的最大值

輸入輸出樣例

輸入 #1
8 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-----------------------