模板 最長不下降子串行

2022-07-23 14:45:18 字數 3065 閱讀 4781

====接力dalao完成====

對前文的一些補充:

首先清楚最長不下降子串行是乙個遞增但是允許不同位元素相等的序列。而最長上公升子串行則是乙個單調遞增的序列。

而兩者都是子串行,所以子串行的長度一定小於等於原序列。且子串行在原序列的位置不一定連續。

這個o(nlogn)的演算法使用的是貪心的思想。

為了幫助理解,請與以下**對比閱讀:

#includeusing

namespace

std;

int a[1000001],dp[1000001

];int

ans;

intn;

intmain()

for(int i=2;i<=n;i++)

ans=max(dp[i],ans);

}cout

return0;

}

這個是o(n2)的暴力演算法,大概思路就是每次選取乙個終點,再暴力求出終點的最長序列值,再從答案中選取最大值。

而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陣列是乙個不下降序列,所以可以用stl中的upper_bound來簡化過程。

(upper_bound在dalao的題解裡已經有解釋,再複製一下)

首先介紹兩個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<>());

乙個小小的問題:

是怎樣保證d陣列中的數在原陣列中的下標也是遞增的呢?

這個問題是不用考慮的,因為最後決定答案的是len,並不是d陣列或是陣列內的元素決定的,d陣列內只是儲存可行的最優解,用來優化答案。

若當前原陣列中存在一條比當前d陣列更長的最長不下降子串行,才會影響最後的答案長度。

這樣問題就不大了(看不懂可以模擬幾組陣列來理解一下)

**:

#include#include

#include

using

namespace

std;

int a[100001],d[100001

],n,len;

intmain()

d[1]=a[1

]; len=1

;

for(int i=2;i<=n;i++)

for(int i=1;i<=n;i++)

cout

/這個是分段輸出,幫助理解

} cout

return0;

}

無注釋的點這裡:

#include#include

#include

using

namespace

std;

int a[100001],d[100001

],n,len;

intmain()

d[1]=a[1

]; len=1

;

for(int i=2;i<=n;i++)

}cout

return0;

}

板子在這裡(優化自己打)

應該就這樣了(看不懂我也。。自己搜吧)

dalao友情提供的例題:(這個hin經典)

(這個超級妙)

掰掰我寫完了@蒔蘿蘿

csp-s rp++!

最長不下降子串行

a1 t0 an a an 1 2 b an c d n 1 求該序列最長不下降子串行長度 n不是很大顯然可以暴力。n很大呢?那就不斷減迴圈節長度直至減到乙個閾值內,再暴力。正確性顯然,只要閾值不要設太小。include include include define fo i,a,b for i a...

最長不下降子串行

最長不下降子串行解法 第一種就是普通的dp方法 for int i 1 i n i dp 0 1 for int i 1 i n i ans max ans,dp i cout 主要記錄一下n logn的寫法 二分 主要思路 用乙個陣列 b 來記錄最長的子串行 一開始讓b 1 a 1 陣列a為輸入的...

最長不下降子串行

例子 openjudge 4977 怪盜基德的滑翔翼 描述怪盜基德是乙個充滿傳奇色彩的怪盜,專門以珠寶為目標的超級盜竊犯。而他最為突出的地方,就是他每次都能逃脫中村警部的重重圍堵,而這也很大程度上是多虧了他隨身攜帶的便於操作的滑翔翼。有一天,怪盜基德像往常一樣偷走了一顆珍貴的鑽石,不料卻被柯南小朋友...