最長上公升子串行
時間限制: 10 sec 記憶體限制:128 mb
題目描述
給定乙個序列,初始為空。現在我們將1到n的數字插入到序列中,每次將乙個數字插入到乙個特定的位置。我們想知道此時最長上公升子串行長度是多少?輸入
第一行乙個整數n,表示我們要將1到n插入序列中,接下是n個數字,第k個數字xk,表示我們將k插入到位置xk(0<=xk<=k-1,1<=k<=n)輸出
1行,表示最長上公升子串行的長度是多少。
樣例輸入 3
0 0 2
樣例輸出 2
提示 100%的資料 n<=100000
o(nlogn)演算法**:
1 #include 2**分析:using
namespace
std;
3int i,j,n,s,t,a[100001];4
intmain()5/*
用t替換
*/22 a[l]=t;23}
24 }/*
最長序列數就是棧的大小
*/25 cout
26 }
第乙個念頭就是用動態規劃,很顯然,這道題的轉移方程非常非常簡單,一目了然,先準備乙個陣列b
b[i]=1;
,從a[1]開始搜到i的最長上公升子串行。
這句賦值語句固然很好理解,每乙個元素,也可以視為乙個符合題意的子串行。
b[2]呢?
如圖,它顯然比a[1]高,在執行如下語句時
for(j=1;ja[j])
j小於i,也就是2,目前符合條件的只有a[1],a[1]又通過了判斷語句,它確實小於a[i],執行下一條語句:
b[i]=max(b[i],b[j]+1);
很顯然:b[2]顯然原來是1,當它和b[1]+1比時,1當然比2小,所以,b[2]自然就是2了。
再來看看時間複雜度:
很明顯,時間複雜度為o(n^2)。
那,這個方法夠快嗎?還可以,但仍然有些不盡人意。
**如下o(n^2):
#include
using namespace std;
int i,j,n,a[100],b[100],max;
int main()
for(max=i=0;imax) max=b[i];
cout那麼,還有沒有更快的方法呢?
當然有,有沒有想到過,為什麼要記錄資料呢?
我們可以模擬乙個stack
在有大量資料的情況下,這演算法效率極高
但是,怎麼來優化程式呢?
我們可以這樣來模擬:
每輸入乙個數,如果這個數大於棧頂的那個數,於是把它推入棧中。
但是,如果這個數大於棧頂呢,這不證明它不可以更新棧中的
某個元素,這時,就可以運用二分查詢了。
有人可能會問:這個序列是無序的啊。沒錯,但查詢的是stack裡面的元素,而這個棧裡的所有元素,都是嚴格遞增的,所以,用二分查詢可以把問題縮減為o(nlogn)。
有些不符合邏輯,不是嗎?15的下標比17、18、20都大,為什麼能插入呢?但是如果仔細想一想,這好像並不影響正常答案,但如果要輸出最長上公升子串行,那就要改一改這個演算法了。
整個二分查詢**如下:
else
a[l]=t; }
由此,這個查詢演算法才得以下降到logn,於是,整體也就是o(nlogn)。
具體操作如下:
每次取棧頂元素和讀到的元素做比較,如果大於,則將它入棧;如果小於,則二分查詢棧中的比它大的第1個數,並替換它。最長序列長度即為最後模擬的大小。
這也是很好理解的,對於i和j,如果i
**(同上):
#include
using namespace std;
int i,j,n,s,t,a[100001];
int main()
a[l]=t;//
如果小於,則二分查詢棧中的比它大的第1個數,並替換它,,,,那17怎麼辦???不理解,為什麼15可以插隊????}}
cout<
最長上公升子串行 LIS 詳解
最長上公升子串行 longest increasing subsequence,lis 在電腦科學上是指乙個序列中最長的單調遞增的子串行。最長上公升子串行是序列,其狀態是一維的,所以我們可以定義狀態 f i 表示以a i 結尾的最長上公升子串行 如果每乙個元素都只考慮它本身,則以a i 結尾的最長上...
最長上公升子串行
問題描述 乙個數的序列bi,當b1 b2 bs的時候,我們稱這個序列是上公升的。對於給定的乙個序列 a1,a2,an 我們可以得到一些上公升的子串行 ai1,ai2,aik 這裡1 i1 i2 ik n。比如,對於序列 1,7,3,5,9,4,8 有它的一些上公升子串行,如 1,7 3,4,8 等等...
最長上公升子串行
最長上公升子串行問題是各類資訊學競賽中的常見題型,也常常用來做介紹動態規劃演算法的引例,筆者接下來將會對poj上出現過的這類題目做乙個總結,並介紹解決lis問題的兩個常用 演算法 n 2 和 nlogn 問題描述 給出乙個序列a1,a2,a3,a4,a5,a6,a7.an,求它的乙個子串行 設為s1...