乙個蒟蒻的掙扎 最長上公升子串行

2022-08-21 08:15:09 字數 3776 閱讀 2269

(被教練壓著寫完的,嚶)

感謝機房大佬jyy友情校對

@kyoko (組織需要你!!!)

大佬填坑啦!!!!!!!!!

老是吞我格式!還吞我字吞我圖!看到空白的不對勁的連不上的地方記得重新整理

下面進入正文(文末有推薦練習的模板題兩題)(介紹的是如何求出序列長度,我沒弄明白這個序列怎麼求)

是什麼呢,就是在乙個原序列中,取出乙個新序列(不一定連續),其元素單調遞增(可以相等)

即: 原序列為 a [ i ] , 對於其最長不下降子串行,任何乙個 i,j (i < j)都有,a [ i ]>= a [ i - 1 ]

例如:原序列 : 1 2 9 8 6 5 4 8 4

最長不下降子串行:1 2 4 8  (或 1 2 5 8、 1 2 6 8、1 2 8 8)

長度為: 4

理解了嗎(其實這個應該都學過的)

過~(過於簡單不放標程,自己試著寫寫,普及難度)

乙個陣列 f 記錄從 i 到 f [ j ] 的最長不下降子串行長度

兩個迴圈巢狀:乙個列舉 i ,乙個列舉 j

最後跑乙個迴圈,找最大值就好

大概能過 n = 10 4 的資料

(想什麼呢提高怎麼肯能有這麼裸的模板這麼水的資料啊)

於是我們進入下一部分也就是重點

(似乎也不是很難結果看部落格就是沒有看懂還麻煩了高二的大佬,嚶)

(據說用線段樹啊樹狀陣列等資料結構優化什麼的,,也能達到這個複雜度,但是啊,我從來都是線段樹能不寫就不寫的)

首先介紹兩個stl,非常好用(用於解決這道題)

(球球你看看它,如果看不懂就先看演算法再看它,超級省事的)

用法:lower_bound(a+1,a+n+1,x)

返回 a 陣列內 第乙個大於等於x 的數的指標

令 p = lower_bound(a+1,a+n+1,x)- a,a [ p ] 則 為第乙個大於等於x 的數

(如果你會指標的話)  * p = lower_bound(a+1,a+n+1,x)也是 第乙個大於等於 x 的數

upper_bound 和它的用法差不多,除了返回的是第乙個大於x 的指標

(也就是求最大不下降子串行最大上公升子串行的差別)

若我們要求下降序列呢 ?

我們可以寫乙個 cmp,或者使用 c++ 自帶的 greater<>() (都在stl裡)

(和 sort 寫法差不多)(sort總該寫過的)

lower_bound(a,a+1,x,cmp) / lower_bound(a,a+1,x,greater<>());

ok!過!進入正式的演算法部分

這個演算法使用的是什麼思想呢,貪心

我們定義乙個陣列 d ,元素依次相等或遞增,維護一段不下降子串行(注意!這個 d 陣列並非最終的不下降子串行,解釋在下面)

長度為 len,len即為最終需要的最長不下降子串行的長度 ,d [ len ] 即為該區間最小值

乙個迴圈 i 從1 列舉到 n,將 a [ i ] 逐一加入我們的 d 陣列

由於這個序列一定不下降,所以當 a [ i ] >d [ len ] 時可以直接加在尾端,(len++),那麼當 a [ i ] < d [ len ] ,怎麼辦呢(又不能不加呀(不加肯定要wa呢))

這時候就需要剛剛花費大量筆墨介紹的 lower_bound與upper_bound 了

由於是最長不下降子串行,可以相等,故採用 upper_bound ,查詢出第乙個大於 a [ i ] 的元素 d [ j ] ,將其替換為 a [ i ] 

至於它的正確性,我就按我的理解隨便說說不能當標準證明過程 

(發現大佬解釋比我清楚!於是粘了過來)

而o(nlogn)的實現過程與這個正好相反。

因為每次暴力更新都會有很多不必要的比對,比如對於原序列

1 2 3 4 5

當前選定的終點是5,在上面的暴力程式中,對於位置5會與1,2,3,4各比較一次,然後得出最後答案。然而,因為這個佇列已經是單調遞增的,所以5只需要與前一位4比對一次就可以得出答案,從而省去前面3次無用的比對。

為了避免浪費時間,這裡再開乙個陣列d來儲存已經找出的價效比最高的最長不下降子串行。

這裡的「價效比」是指如果採用當前這個子串行作為既定的開頭,用於下面繼續比對,這樣得出的答案一定是最優的

舉例來說:

對於原序列:

1 2 5 7 8 1 10

有下列子串行

a:1 5 7 8

b:1 2 5 8 

稱b的價效比高於a,其原理是,對於b陣列中相鄰兩個元素的差要小於a陣列中的,而且最後乙個元素要比a陣列的小,此時稱b的價效比比a高。

而對於價效比更高的序列,再接著處理時,最終所得的結果是最優的。(有最優子結構

而對於任意乙個位置,若在原序列中的a[i]>d[len],其中len為d的長度,那麼d[len++]=a[i];

這個的原理很簡單,但是當a[i]去尋找d陣列中第乙個第乙個大於a[i]的數,讓a[i]與該數互換位置,得到價效比更高的序列,這次操作的原因已經在上文中闡述過。

因為 d 陣列是有序的,所以 d [ j ] 一定是d [ 1-j ] 中的最大值,由於我們要求得是最長的序列,根據貪心思想,那麼末尾的數越小越好(方便接更多的數),由於 a [ i ] < d [ j ] ,那麼將其替換為 a [ i ] 顯然更優

證明:d 陣列不是最終的序列

因為 替換的 a[ i ] ,在原數列中的下標明顯大於 d [ j ],所以它的下標不一定小於d[j+1/j+2/j+……n],不滿足條件

證明看不明白無所謂啦,畢竟我們不考證明,了解它的思想指導怎麼用就好了嘛(大霧)

最壞的情況下每次都要二分查詢(複雜度為 log 級),一共要往裡填 n 次數,故時間複雜度為o ( n log n)

**參考待填充

根據我做題時的判斷,一般學習演算法的時候了解它的思想、實現過程、考場會打就好

了解它的思想、原理和實現過程,會在你考試做題看到那種莫名其妙的題(感覺啥也不像,只能打莫得分的暴力(暴力也打不好的題我們乖乖放棄就好啦))時能夠想到,它的更新過程類似於某種演算法,從而想出正解哦!!!開心嗎!!!!!!(最近寫了兩題有感而發)

至於考場會打,你考場寫不出來等於白學!費心費力費頭髮還莫得好分數,你想想難不難受(我是個蒟蒻只能說出來這些啦)

學會了這個,你就可以類推類推求出

最長上公升子串行,最長不上公升子串行,最長下降子串行……(都是改個符號就完事)

然後推薦兩道題目,都是很適合練手的,難度也就那樣

洛谷飛彈攔截 一道黃題,基本上是個模板,也是書上的例題好像,題解非常棒很值得一看

這個目前只有題解(我寫的版本),不過裡面有題面的!!!(我也不知道這題**的不過一搜題解還蠻多!)很妙的一題!!

好的囉嗦了這麼久,也就這些啦

祝我自己,也祝認真看到這裡的你

ありがとうございます

最後的最後(抱歉打擾了)

這篇部落格是我看了洛谷的題解以及搜尋許多講解的部落格後用自己的思路總結概括的,嗯,就醬

最長上公升子串行的個數

注意 這裡要求值不同。先去重,去掉連續一段相同的數字,只保留乙個,儲存在陣列 a 裡,並用陣列 c i 表示a i 在原始資料中連續出現的個數。用 f i 表示陣列 a 中以a i 為結尾的最長上公升子串行的長度是多少 用g i 表示陣列a中以a i 為結尾的最長上公升子串行的個數。在處理 f i ...

最長上公升子串行的變化

題目 hdu1160 題意 一群老鼠,每個老鼠有兩個引數 重量和速度。尋找重量遞增且速度遞減的最長的子串行,輸出該序列的座標順序。解答 先排序,然後最長上公升子串行。注意 排序後坐標會改變,因此,應當在結構體中引入乙個新的變數index,儲存它的原始位置。儲存路徑 記錄比當前位置小的上乙個位置的左邊...

最長上公升子串行的和

總時間限制 1000ms 記憶體限制 65536kb 描述乙個數的序列bi,當b1 b2 bs的時候,我們稱這個序列是上公升的。對於給定的乙個序列 a1,a2,an 我們可以得到一些上公升的子串行 ai1,ai2,aik 這裡1 i1 i2 ik n。比如,對於序列 1,7,3,5,9,4,8 有它...