51nod1134(最长递增子序列)

题目链接: https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1134

题意: 中文题诶~

思路: 直接暴力的话时间复杂度为O(n^2), 本题数据量为 5e4, 恐怕会超时;

我们维护当前最长的长度len, 用vis[j]存储长度为 j 的所有子序列中最小的末尾数值, 那么对于当前数据 a[i] , 如果数组vis中存在比其大的元素我们用a[i]替换掉vis中第一个比a[i]大的数, 若不存在,那么我们将a[i]加入 vis 末尾, 此时 vis 数组长度加一. 如此我们便维护了数组 vis 的性质, 最终得到的len就是答案了. 因为数组vis是递增的, 所以我们在查找时可以用二分(本人习惯用 upper_bound()), 那么时间复杂度便降为了 O(n*loglen).

代码: 

 1 #include <bits/stdc++.h>
 2 #define MAXN 50010
 3 using namespace std;
 4 
 5 const int MIN=-1e9;
 6 
 7 int main(void){
 8     int n, a[MAXN], vis[MAXN], len=1; //vis[i]表示长度为i的数列中最小的末尾值
 9     scanf("%d", &n);
10     for(int i=0; i<n; i++){
11         scanf("%d", &a[i]);
12     }
13     for(int i=0; i<=n; i++){
14         vis[i]=MIN;  //注意本题数据范围是 -1e9~1e9
15     }
16     vis[1]=a[0];
17     for(int i=1; i<n; i++){
18         cout << endl;
19         int pos=upper_bound(vis+1, vis+len+1, a[i])-vis;
20         vis[pos]=a[i];
21         if(len<pos){ //维护最大长度
22             len=pos;
23         }
24     }
25     printf("%d
", len);
26 }
原文地址:https://www.cnblogs.com/geloutingyu/p/6216881.html