nyoj 214 - 单调递增子序列(二)

 http://acm.nyist.net/JudgeOnline/problem.php?pid=214

单调递增子序列(二)

时间限制: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

经典的求最长递增子序列的时间复杂度为o(n^2)的算法就不用多说了,在第四届校赛第四题中涉及到。但是这个还用o(n^2)的算法明显会超时,因此要用优化的算法来写这道题。优化的原理就不多说了,好多博客里边写的都有,向大家推荐一篇我看到的并且认为比较详细的一篇文章:http://blog.sina.com.cn/s/blog_4e005abd01000980.html。在进行查找时用二分查找可以将时间复杂度优化为o(nlogn)。

代码如下:

 1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 using namespace std;
5 int a[100002];
6 int d[100002];
7 /*int binarysearch(int num, int n)
8 {
9 for(int i = 1; i <= n; i++)
10 {
11 if(d[i] >= num)
12 break;
13 }
14 return i;
15 }这是不用二分法的查找,o(n^2),会超时*/
16 int binarysearch(int num, int len)
17 {
18 int left, right, mid;
19 left = 1;
20 right = len;
21 mid = (left + right) / 2;
22 while(left <= right)
23 {
24 if(d[mid] < num)
25 left = mid + 1;
26 else if(d[mid] > num)
27 right = mid -1;
28 else
29 return mid;
30 mid = (left + right) / 2;
31 }
32 return left;
33 }//o(nlogn)
34 int main()
35 {
36 int n, len, i, j;
37 while(scanf("%d", &n) != EOF)
38 {
39 for(i = 0; i < n; i++)
40 scanf("%d", &a[i]);
41 memset(d, 0, sizeof(0));
42 len = 1;
43 d[1] = a[0];
44 d[0] = -1000000;
45 for(i = 1; i < n; i++)
46 {
47 j = binarysearch(a[i], len);
48 d[j] = a[i];
49 if(j > len)
50 len = j;
51 }
52 printf("%d\n", len);
53 }
54 return 0;
55 }

 

 

posted @ 2012-01-20 13:56  枫萧萧  阅读(587)  评论(0编辑  收藏  举报