51nod 1134 最长递增子序列 (O(nlogn)算法)

基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题
 收藏
 关注
给出长度为N的数组,找出这个数组的最长递增子序列。(递增子序列是指,子序列的元素是递增的)
例如:5 1 6 8 2 4 5 10,最长递增子序列是1 2 4 5 10。
 
Input
第1行:1个数N,N为序列的长度(2 <= N <= 50000)
第2 - N + 1行:每行1个数,对应序列的元素(-10^9 <= S[i] <= 10^9)
Output
输出最长递增子序列的长度。
Input示例
8
5
1
6
8
2
4
5
10
Output示例
5

常规的解法是设dp[i]表示前i位的最长上升序列长度,然后每次更新dp[i+1]都要与[0,i]进行一次比较。
时间复杂度为O(n^2),完美超时。

想想怎么去优化呢?看看更新dp[i+1]需要比较这么多次吗?假设dp[i+1]=len,那么我们只要与值为len-1的去
进行比较,所以不妨设b[i]表示最长上升序列为i的dp数组中的最小值。

 1 /*用数组b来存放最长上升序列,然后枚举数组a中元素看能否插入b数组。
 2 那么b数组的大小即为所求。
 3 */
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <cstring>
 7 using namespace std;
 8 typedef long long ll;
 9 ll b[50005];
10 ll a[50005];
11 ll n;
12 void solve()
13 {
14     memset(b,0,sizeof(b));
15     b[0]=a[0];
16     int sum=1;
17     for(int i=1;i<n;i++)//枚举a数组
18     {
19         int pos=lower_bound(b,b+sum,a[i])-b;//lower_bound()返回值为b数组中有几个比a[i]小的
20         b[pos]=a[i];                                //或者理解为用a[i]去更新b序列应更新的位置
21         sum=max(sum,pos+1);//长度更新
22     }
23     cout<<sum<<endl;
24 }
25 int main()
26 {
27     cin>>n;
28     for(int i=0;i<n;i++)
29         cin>>a[i];
30     solve();
31     return 0;
32 }
代码才是最清晰的语言
原文地址:https://www.cnblogs.com/onlyli/p/7242906.html