建立乙個陣列res[maxn], res[ i ]用來記錄以i位置為結尾的最長的子串行,那麼我們要求res這個陣列裡的最大值(注意不是res[ n ] ),所以當我們在求res[ i ] 時,需要從0到i-1掃一遍,看看通過哪個點「鬆弛」 (因為這個演算法好像迪科斯徹最短路,所以借用這個名詞來解釋一下),這樣**如下
#include
#include
using
namespace std;
const
int max=
1001
;int a[max]
;int res[max]
;int
main()
cout<}
借鑑大佬的部落格,優化講的實在太好了!(傳送門)
那麼,有沒有更快的方法呢?當然有。這回要用到二分。
我們回想一下,在上面 o(n2) 的程式中,哪些地方看起來比較費時?
沒錯,就是內層用於更新i的迴圈。因為每一次他都要查詢一遍,效率並不高。
回到題目,我們發現,他只要我們求長度,所以我們可以模擬乙個單調棧(曾經很多參考書說這是乙個棧。實際上不是嚴格的棧,而是乙個後進入的加在末尾,然後每次可以替換掉其中元素的序列。這個序列是單調遞增的,保證結果就是所求的lis)。
所以每遇到乙個比棧頂元素大的數,就放進棧裡,遇到比棧頂元素小的就二分查詢前邊的元素,找到乙個「最應該被換掉的元素」,用新數去更新前邊的元素。這個元素可能不是最優解的一部分,但是它可以使得後面還未加入的、比較小的數更有可能進入這個佇列。通俗地來說,作為門檻,他本來要大於當前序列的最後乙個數才能加進去;就是如果我太大了,我就乖乖呆在末尾;如果前面有乙個數比我大,也就是我比你好,既然我在你後面也就是我們兩者只能選其一,那我只好把你替換掉了。雖然我這臨時臨頭換的不一定最合適,但是對於後面還有很多的人等著排進來的情況下,我給他們創造了更多機會,使得這個序列的最後乙個數有可能變小,讓更多的人進來。
這個演算法不難證明也是正確的。因為前面每一次的列舉都換成了二分,內層的複雜度從n降到了log2,外層不變。所以總的複雜度是o(nlog2n)。
#include
#include
using
namespace std;
int v[
200001];
int res[
200001];
intmain()
} cout<}
LIS 最長上公升序列(DP 二分優化)
求乙個數列的最長上公升序列 動態規劃法 o n 2 1 dp 2int lis int a,intn 3 16 17 18return cnt 1 因為初始化為0,所以返回結果 1 19 貪心 二分法 o nlogn 分析 要讓乙個序列具有最長上公升子串行,其實就是保證子串行中的每個元素盡可能小,降...
LIS 最長上公升子串行 (二分優化)
題目 長度為n的序列a1,a2,an,選出滿足 j i 時,a j a i 最長子序列 分析 當選擇第i個時候,在j狀態 dp i 表示以i為終點的最大上公升序列 轉移方程 dp i max include include include include include include includ...
1081 最長上公升子串行 (dp 二分)
pipi又來考大家最長上公升子串行問題了 不過這次它想為難一下你 給你乙個整數序列,包含n個整數,要你求最長上公升子串行的長度 多組輸入 第一行為乙個整數n,1 n 1000000 第二行包括n個整數,每個整數均在int範圍內 輸出乙個整數,表示最長上公升子串行的長度。51 2 5 4 7 incl...