最長上公升子串行問題是解決很多問題的根本,它能幫助你理解二分的思想。
考慮一下:對於乙個序列 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)
))了,為我們節省了很多時間.
**實現
你可能會問了:有沒有更簡潔的寫法來實現這樣高效的二分呢?答案是有的.在我們的c++ stl庫中就有這樣的函式,來幫助我們實現查詢.#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;
}
在< algorithm > 庫中,有個叫lower_bound的函式,先看他的函式定義:
template< class forwardit, class t >
forwardit lower_bound( forwardit first, forwardit last, const t& value );
它的功能是:
返回指向範圍 [first, last) 中首個不小於(即大於或等於) value 的元素的迭代器,或若找不到這種元素則返回 last 。
那麼我們有了這個工具之後就可以這樣改進我們的程式,讓它更簡潔.
這樣就將二分的過程運用stl函式省去了,提高了我們的程式設計效率.#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;
}
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 ...