Description
给出长度为N的数组,找出这个数组的最长递增子序列。(递增子序列是指,子序列的元素是递增的)
例如:5 1 6 8 2 4 5 10,最长递增子序列是1 2Input
第1行:1个数N,N为序列的长度(2 <= N <= 50000)
第2 - N + 1行:每行1个数,对应序列的元素(-10^9 <= S[i] <= 10^9)Output
输出最长递增子序列的长度
Sample Input
8 5 1 6 8 2 4 5 10
Sample Output
5
Source
题解
很明显,数据量比较大,不能采用二维的求最长单调子序列
那么设dp[i]为长度为i的最长单调子序列的最小结尾,那么dp数组是单增的
那么如果a[i] > dp[idx] ,说明可以接上,dp[idx + 1] = a[i]
否则,说明不能接上,那么看它可以接在哪里,也就是找到一个小于a[i]的dp[idx],二分即可
复杂度O(n*log(n));
代码
#include <set>#include <map>#include <list>#include <cmath>#include <ctime>#include <deque>#include <queue>#include <stack>#include <cctype>#include <cstdio>#include <string>#include <vector>#include <cassert>#include <cstdlib>#include <cstring>#include <sstream>#include <iostream>#include <algorithm>#define pi acos(-1.0)#define maxn (10000000 + 5)#define mol 1000000007#define INF 1e20#define Lowbit(x) (x & (-x))using namespace std ;typedef long long int LLI ;int dp [ maxn ];int arr [ maxn ];
int LIS ( int n ){int idx = 0 ;dp [ idx ++ ] = arr [ 0 ];for ( int i = 1 ; i < n ; i ++ ){if ( arr [ i ] > dp [ idx - 1 ]) dp [ idx ++ ] = arr [ i ];else {int where = lower_bound ( dp , dp + idx , arr [ i ]) - dp ;dp [ where ] = min ( dp [ where ], arr [ i ]);}}return idx ;}
int main () {// freopen("in.txt","r",stdin);// freopen("out.txt","w",stdout);int n ;scanf ( "%d" , & n );for ( int i = 0 ; i < n ; i ++ ){scanf ( "%d" , & arr [ i ]);}printf ( "%d \n " , LIS ( n ));return 0 ;}