給定乙個序列,求最長不下降子串行的長度
定義:a[1…n]為原始序列,dp[k]表示長度為k的不下降子串行末尾元素的最小值,len表示當前已知的最長子序列的長度
初始化:dp[1] = a[1]; len = 1;
現在我們已知最長的不下降子串行長度為1,末尾元素的最小值為a[1],那麼我們讓i從2到n迴圈,依次求出前i個元素的最長不下降子串行的長度,迴圈的時候我們只需要維護好dp這個陣列和len就可以了
重點是怎麼維護
我看了很多很多博主講的關於這個演算法,最後看到了這樣一篇部落格,感覺博主寫的超級棒,搞明白之後就有了這一篇部落格原版
新加進來乙個元素a[i]
如果這個元素大於等於dp[len],那就直接加到序列的末尾
dp[++len] = a[i] 即可
那如果這個元素a[i]小於dp[len]呢,那就說明之前的元素可能滿足不了len最大,那麼就需要找到乙個更有潛力,可以得到更優解的數把他替換掉
例如兩個數a[x] a[y] x < y 且a[x] < a[y] 且 dp[x] == dp[y]
這時候明顯選擇a[x]更有潛力,因為可能存在a[x] < a[z] < a[y]的情況,選擇a[x]可以得到更優的解
所以就是當陣列dp的值相同的時候,盡量選擇更小的a[x]
這個更有潛力的數就是在dp陣列中第乙個大於當前的a[i]的,第乙個意味著前面的都小於等於他
假設第乙個大於他的是dp[j],說明dp[1…j-1]都小於等於它,那麼它完全可以接上dp[j-1]然後生成乙個長度為j的不下降子串行,而且這個子串行比當前的dp[j]這個子串行更有潛力(因為這個數比dp[j]小)
所以就替換掉它就行了,也就是dp[j]=a[i]
尋找第乙個大於等於他的數
可以stl upper_bound 每次複雜度 logn
int a[
40005];
int dp[
40005];
intmain()
dp[1]
= a[1]
;//初始化
int len =1;
for(
int i=
2;i<=n;i++)}
printf
("%d\n"
,len)
;return0;
}
一道最長不下降子串行的板子題 最長不下降子串行LIS
最長上公升子串行問題是解決很多問題的根本,它能幫助你理解二分的思想。考慮一下 對於乙個序列 n nn 請你查詢n nn中最長的子串行a aa,使得任意 i i j 時 a i a i a i a i a i a i 例如乙個長度為5 55的n nn 5553 331112 22444 顯然,它的最長...
LIS最長不下降子串行
在乙個序列中找到乙個最長的子串行 可以不連續 使得這個子串行不下降,即非遞減的。核心部分找到狀態轉移方程 dp i max j 1,2,i 1 a j 附上我的 include include includeusing namespace std const int maxn 10010 int d...
最長不下降子串行 (LIS)
最長不下降子串行是這樣乙個問題 在乙個數字序列中,找到乙個最長的子串行 可以不連續 使得這個子串行是不下降 非遞減 的。令dp i 表示以a i 結尾的最長不下降子串行的長度,這樣對a i 來說就會有兩種情況。1 如果存在a i 之前的元素a j jdp i 2 它前面的元素均比它大,則dp i 1...