最長 上升/下降/不上升/不下降 子序列長度
1.lower_bound & upper_bound
Ⅰ 作用
兩者均屬STL函式,在標頭檔案 algorithm 中
假設我們查詢x,那麼:
lower_bound會找出序列中第一個大於等於x的數
upper_bound會找出序列中第一個大於x的數
沒錯這倆就差個等於號╮(╯▽╰)╭
Ⅱ 用法
以下都以lower_bound做栗子 (因為upper_bound做出的栗子不好吃)
(兩者使用方法同理)
它們倆使用的前提是一樣的:序列是有序的
對於一個數組a,在[1,n]的區間內查詢大於等於x的數(假設那個數是y),函式就寫成:
lower_bound(a + 1, a + 1 + n, x);
函式返回一個指向y的指標
看著是不是很熟悉?回想sort使用的時候:
sort(a, a + 1 + n, cmp);
這裡a+1,a+1+n的寫法是不是很像?
STL裡面的函式寫區間一般都這個尿性
同樣的,lower_bound和upper_bound也是可以加比較函式cmp的:
lower_bound(a + 1, a + 1 + n, x, cmp);
到這裡不得不說說前面的"有序序列",這裡的"有序"是對什麼有序?
你可能已經猜到了,它是對於比較器有序,並且必須是升序!
(為什麼不是降序?這個你可能要去問問寫STL的人)
一旦對降序序列使用lower_bound,就會出現神奇的錯誤,具體原因可以看這篇:
https://blog.csdn.net/qq1337715208/article/details/81072709
當然比較器預設也是"<"
如果要在一個下降序列裡尋找一個小於x的數呢?
根據我們之前說的,lower_bound只能對上升序列使用,那我假裝下降序列是個上升序列就行了嘛~
(lower_bound:你當我傻嗎)(w1049:沒錯我就當你傻)
只需要把比較器改成">":
同時需要寫一個函式cmp:
bool cmp(const int& a,const int& b){return a > b;}
當然,你也可以這樣:
lower_bound(a + 1, a + 1 + n, x, greater <int> () );
這裡的greater
它們的實現方式是二分查詢 ,存在的意義就是讓我們寫程式碼更方便地偷懶(一行lower_bound比寫二分查詢方便多了)
Ⅲ返回值
對於返回值我們有兩種處理方式:
第一種:
許多人討厭指標,那麼我們用這個指標減去陣列開頭的指標(即陣列名),得到兩個指標的差,就是陣列下標,即:
int p = lower_bound(懶得寫) - a;
那麼a[p]就是要找的y
(如果不知道為什麼就記著好了)
第二種:
指標好!指標妙!
改革春風吹滿地,用指標的oier真爭氣!
(以上兩行你可以當做什麼都沒看見)
int *p = lower_bound(還是懶得寫);
那麼*p就是要找的y
可以看出指標多麼直接,不像陣列下標還要倒騰一遍
總結一下:
好像沒什麼可總結的QwQ
對一個下降序列a
int p = lower_bound(a + 1, a + 1 + n, x, greater <int> () ) - a;
a[p]即a[1]到a[n]中第一個小於等於x的數
(被遺忘的upper_bound表示不服)
2.nlog(n)演算法實現
Ⅰ實現方法
首先我們需要一個數組a,儲存從第1個到第n個導彈的高度
然後一個數組d(其實是個棧),儲存不上升序列
把a中的每個元素挨個加到d裡面:
(a中第i個元素為a[i],d長度為len,d中最後一個(也是最小的一個)為d[len])
如果a[i] <= d[len],說明a[i]可以接在d後面(而整個d還是有序的),那就簡單粗暴地把a[i]丟進d:
d[++len] = a[i]
如果a[i] > d[len],說明a[i]接不上
但是我們發揚瞎搞精神:接的上要接,接不上創造條件也要接!
強行把a[i]塞進去:
在d中找到第一個小於a[i]的數,把它踹了,用a[i]代替它!(為什麼正確在下面)
假設這個數是y,怎樣踹掉它呢?
很明顯,我們需要使用lower_bound和upper_bound來查詢
第一步,找一個聽起來無比正確的理由,比如它佔著位置不幹活啦,幹起活來還不如a[i]啦,naive啦,它too young啦,too simple啦......反正能騙過lower_bound和upper_bound就行
(lower_bound&&upper_bound:你當我們傻)(w1049:真聰明)
接下來,特別有正義感的lower_bound和upper_bound就會去把y給拎出來
第二步,考慮使用什麼
我們知道,要求的是最大不上升子序列長度,也就是如果兩個元素相等也是可以的
所以我們踹人就不用踹等於a[i]的了
結合上面,應該使用upper_bound(終於想起來它了)並且使用>作為比較器(這是個下降序列)
第三步,直接開搞
int p = upper_bound(d + 1, d + 1 + len, a[i], greater<int>()) - d;
d[p] = a[i];
成功把a[i]塞了進去
Ⅱ 為什麼正確
若被替代掉的即為最大不上升子序列中的某一元素
那麼替代者與剩下的元素的關係依然滿足與被替代者的關係,顯然成立(也就是說替代者可以完全替代被替代者,並且擁有更廣泛的天空)
為什麼說是更廣泛的天空?
因為被替代者可以取到的範圍更大,它不僅可以做到代替作用,同時可以更新自己的序列,做到一箭雙鵰
這也就是為什麼這個演算法只能求長度而不能求具體的陣列
實際上,d[i] 的含義是:最大不上升子序列長度為 i 時,最優的結尾元素。