单调递增子序列(二)
时间限制:
1000 ms | 内存限制:
65535 KB
难度:
4
- 描述
-
给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度。
如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5。
- 输入
-
有多组测试数据(<=7)
每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=100000)。
数据以EOF结束 。
输入数据保证合法(全为int型整数)! - 输出
- 对于每组测试数据输出整形数列的最长递增子序列的长度,每个输出占一行。
- 样例输入
-
7 1 9 10 5 11 2 13 2 2 -1
- 样例输出
-
5
1
-
-
本来想使用传统动态规划的方式,数据量过大导致超时,才发现用二分法求解
-
原理就是用maxv数组来存储最长递增子序列,如果找到某个数对应的位置可以更新,如果后面有更长的递增子序列,那么就会将之前的递增子序列全部覆盖
-
#include <bits/stdc++.h> using namespace std; const int N = 100010; int dp[100010]; int num[100010]; int find_w(int x, int len) { int l = 1, r= len; while(l <= r)//注意!! { int mid = (l+r)/2; if(dp[mid] == x) return mid; else if(dp[mid] > x) r = mid-1; else l = mid+1; } return l; } int main() { int n; while(~scanf("%d", &n)) { for(int i = 1; i <= n; i++) { scanf("%d", &num[i]); } int len = 1; dp[len] = num[1]; for(int i = 2; i <= n; i++) { if(num[i] > dp[len]) { dp[++len] = num[i]; } else { int pos = find_w(num[i], len); dp[pos] = num[i]; } } cout << len << endl; } return 0; }