最長上公升子串行問題是解決很多問題的根本,它能幫助你理解二分的思想。
考慮一下:對於乙個序列 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 ...