牛客練習賽68 A 牛牛的Mex

2022-05-11 01:15:50 字數 3418 閱讀 3655

傳送門給乙個0~n-1的排列,q個詢問,詢問區間的mex。

mex定義為最小未出現的自然數。

我們隊三個人看到這題第一反應上莫隊,jhlp哈哈哈哈

然後掏出莫隊板子火速a了

我是賽後再來回顧的,發現由於這題陣列比較特殊是有更符合這道題背景的做法的。

首先考慮莫隊做法

莫隊的話首先要對詢問區間排個序,然後主要就是考慮add和del函式怎麼寫。

用乙個cnt陣列記錄在當前區間某個數出現過的次數,tmpans代表當前區間的mex,初始置為0

①add,區間擴充套件的時候,擴充套件的這個位置上的這個數的cnt++。考慮這一位的cnt++會給答案造成什麼樣的影響呢?

影響就是

(1)如果當前這個位置就是原來的mex的話,那原來的這個mex就不成立了,我還得重新尋找新的mex,由於之前的mex是之前區間最小的沒有出現過的自然數,那麼小於mex的值不可能成為新的mex,所以乙個while迴圈往大於mex的方向尋找,直到碰到乙個cnt為0的數停止找到當前的mex。

(2)如果當前位置不是原來的mex,

​ 1.是比mex大的數顯然不會影響mex的值。

​ 2.如果是比mex小的值也不會影響mex,因為mex之所以是mex,就是因為比他小的都已經出現過了,所以比他小的再出現也不會影響什麼。

②del,區間收縮的時候,收縮位置的值的cnt--,會對答案造成什麼樣的影響呢?

影響就是,

1.如果當前位置的cnt--之後變為0了,就有可能成為新的mex。設當前位置為x,當前位置的值為a[x]

(1)a[x]>mex,那麼mex不變;

(2)a[x](3)不可能,因為mex不可能在當前區間存在。

2.如果當前位置的cnt--之後沒有變為0,那麼顯然對答案不會產生影響。

以上,add和del就討論完了。下面是學習莫隊以及寫這道題碰到的一些坑點

坑點1.四個while迴圈一定要先add再del,防止cnt陣列變為負數,你可能會覺得變為負數怎麼了,反正最後會變回來,nonono,在此感謝ztc大佬替我想的wa樣例。

5 1

2 0 1 3 4

3 5

你會發現如果先del你的答案可能會變成2

因為cnt變為負數,使得這個cnt有可能在add的過程中變到0,而這又是我們在上面的add中沒有討論到的情況,因此需要先add再del盡可能保證答案的正確性,以免意外的發生。

2.這個坑點雖然我沒有遇到過,但是ztc大佬提了一嘴,我就寫下來為以後的莫隊不停地t或者wa的時候提供一種錯誤可能性的參考吧,就是用莫隊的奇偶優化的時候有可能會產生一些越界問題什麼的,t掉,bshd啦

3.wa的時候可以嘗試換個query的cmp函式,可能就過了,也是作為乙個嘗試的方向吧

**

/****************************

* author : w.a.r *

* date : 2020-08-30-01:21 *

****************************/

/*莫隊求區間mex

*/#include#include#include#include#include#include#include#includeusing namespace std;

typedef long long ll;

const int maxn=3e6+10;

const ll mod=1e9+7;

namespace fast_ioelse return (*iois++);

}void write()

void putchar(char x)

inline int read()

inline long long read_ll()

template void print(int x, char ch = '\0')

void getstr(char *s, int &l)

void putstr(const char *s)

int tmpans=0,k,ans[maxn];

inline void add(int x)

inline void del(int x)

ll calc()

int main()

for(int i=1;i<=q;i++)printf("%lld\n",ans[i]);return 0;

}

此題正解是維護陣列的字首最小值pre和字尾最小值suf,對於每乙個詢問[ l , r ],\(min(pre[l-1],suf[r+1])\)就是答案。

為什麼呢?

因為題目中規定了給出的是乙個\([0,n-1]\)的排列,0~n-1的數全都會出現,且每個數隻會出現一次。

因此對於詢問的區間的mex,首先區間裡的數不可能是答案,答案只可能在除詢問區間外的部分產生。

詢問區間外的數首先滿足了區間未出現過這個條件,那如何滿足最小這個條件呢?就取min就可以啦,所以詢問區間左邊的部分用pre字首最小值陣列維護,詢問區間右邊的部分用suf字尾最小值維護答案,最後二者取個min就是答案啦。

注意點如果詢問的是整個區間的話那麼答案一定是n,所以需要在pre[0]和suf[n+1]的位置賦值為n

這樣答案就很完美啦

**

/****************************

* author : w.a.r *

* date : 2020-08-30-01:21 *

****************************/

/**/

#include#include#include#include#include#include#include#includeusing namespace std;

typedef long long ll;

const int maxn=1e5+50;

const ll mod=1e9+7;

namespace fast_ioelse return (*iois++);

}void write()

void putchar(char x)

inline int read()

inline long long read_ll()

template void print(int x, char ch = '\0')

void getstr(char *s, int &l)

void putstr(const char *s)

}

本來就想著回顧一下莫隊

結果就感覺增加了好多奇怪的知識,果然要保持一顆好奇的心哦

我發現自己莫隊還是不太會寫啦,就很離譜,主要是碰到新的題目就不會該add和del。還有就是大佬告訴我正常的莫隊求mex應該要再套個分塊或者線段樹,否則這樣純暴力是可以被卡掉的,有空再學學怎麼寫更新上來吧(咕咕咕~

牛客練習賽 68

n,q 105 0 a i ai互不 相同 n,q 10 5,0 a in,q 10 5,0 aiai 互 不相同後面兩個條件非常重要,通過後面兩個條件將問題轉化為乙個區間內最小未出現的自然數就等於不在這個區間內最小出現的自然數對於區間 l,r l,r l,r 只需要算出 1,l 1 和 r 1,n...

牛客練習賽63 B牛牛的魚缸

題目描述 牛牛有乙個長為l,寬為1,高為h的魚缸,現在他想要在魚缸中盛一些水。他想要知道這個魚缸最多能夠放多少水。當然這個問題太過於簡單,所以牛牛將這個魚缸放到了乙個長為l,高為h的斜坡上面,如圖所示,魚缸寬度為1的這條邊緊緊靠在斜坡與地面的交界線上。在不允許移動魚缸與斜坡的情況下。魚缸最多能夠放多...

牛客練習賽63 牛牛的樹行棋

題意如上 思路 很好的一道樹上博弈。首先需要看出來是sg博弈 並且知道sg博弈 知道之後 如果能猜到sg函式的表示就差不多啦,結論是 sg x 到達子樹中最深的葉子節點的長度。那麼怎麼猜呢?葉子節點無法在向下延伸,sg 0.那麼葉子節點的father只能向下延伸一步,合理的猜想過後sg 1。之後ba...