最長不下降子串行LIS

2021-08-28 06:20:50 字數 3362 閱讀 6355

最長上公升子串行問題是解決很多問題的根本,它能幫助你理解二分的思想。

考慮一下:對於乙個序列 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;

顯然,它的最長不下降子串行就是 1112

22444.

我們可以想一下自己是如何看出它的最長不下降子串行的.

首先,第乙個數是5

55,前面沒有數,所以它可以是子串行的一部分,那麼我們可以將它放到考慮的第一位:

5

55 ? ? ? ?

因為放了乙個數,所以答案要加一:

a ns

=1

ans=1

ans=

1第二個數是3

33,有兩種選擇,一種是插入到剛插入的數的後面,第二種就是替換掉5

55.因為5

>

35>3

5>

3,所以3

33不可以放到5

55的後面去.5

55比3

33大還在答案中,那我要你5

55有什麼用?果斷替換:

3

33 ? ? ? ?

a ns

=1

ans=1

ans=

1第三個數是1

11,與3

33同理,替換:

1

11 ? ? ? ?

a ns

=1

ans=1

ans=

1第四個數是2

22,比剛插入的數小,可以插入,那麼就變為:

1 112

22 ? ? ?

a ns

=2

ans=2

ans=

2第五個數同理插入:

1 112

224

44 ? ?

a ns

=3

ans=3

ans=

3至此,我們的大腦(?)

(?)(?

)處理完了這樣乙個長度為5

55的最長不下降子串行,當長度很小時我們能順利解決,剩下的就交給計算機啦.

在我們模擬的時候,有這樣乙個操作,當新讀入的數字小於答案數列的第ans

ansan

s個數的時候,我們需要找到要用讀入數字替換掉的位置.這個時候,選擇從第1

11個數挨個比對到第ans

ansan

s個數就很睿智 ,於是我們選擇二分求解.

看這樣乙個序列:

1 112

224446

668

8810

1010

假設新讀入的數是3.

那麼我們取這個元素個數為6

66的序列的中間數: 4444

44比3

33大,而這個序列是單調遞增的,要替換的位置一定在左側.我們取左側的序列.

1 112

224

44中間數為2

22, 2

<

32<3

2<

3,那麼我們取右側的序列

4

44可以判斷,序列中只有乙個元素,要替換的數就決定是它啦!

這樣子尋找就省去了o(n

)o(n)

o(n)

的複雜度轉為ooo(

((log

loglo

gn)

))了,為我們節省了很多時間.

**實現

#include

#include

#define maxn 100001

#define minn -99999

using

namespace std;

int n,a[maxn]

,f[maxn]

,ans;

//f陣列就相當於上面的答案陣列,a陣列存的是數的值.

intmain()

f[0]

=minn;

for(

int i=

1;i<=n;i++

)else

else

} f[l]

=a[i]

;//最後替換}}

printf

("%d\n"

,ans)

;return0;

}

你可能會問了:有沒有更簡潔的寫法來實現這樣高效的二分呢?答案是有的.在我們的c++ stl庫中就有這樣的函式,來幫助我們實現查詢.

在< algorithm > 庫中,有個叫lower_bound的函式,先看他的函式定義:

template< class forwardit, class t >

forwardit lower_bound( forwardit first, forwardit last, const t& value );

它的功能是:

返回指向範圍 [first, last) 中首個不小於(即大於或等於) value 的元素的迭代器,或若找不到這種元素則返回 last 。

那麼我們有了這個工具之後就可以這樣改進我們的程式,讓它更簡潔.

#include

#include

#include

#include

#define maxn 100001

using

namespace std;

int n,a[maxn]

,f[maxn]

,ans;

intmain()

memset

(f,10000

,sizeof f)

;//要初始化的大,後面的比較就不會因為值為0出錯

f[0]

=-1;

//vis[0]除外,它要設為-1

for(

int i=

1;i<=n;i++

)printf

("%d\n"

,ans)

;return0;

}

這樣就將二分的過程運用stl函式省去了,提高了我們的程式設計效率.

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...

最長不下降子串行LIS

lis 題解 最長不下降子串行,英文縮寫為 lis longest increasing subsequence 其 定義是,設有由 n 個不相同的整數組成的數列,記為 a 1 a 2 a n 且 a i a j i j 例如 3,18,7,14,10,12,23,41,16,24。若存在 i1h ...