POJ1631解题报告

这道题目和前面两道是类似的,如果采用相同的方法去解,会出现TLE。前面的方法时间复杂度是O(n^2)的,这道题目,我们要采用的方法是O(nlogn)的。思路想法儿也比较简单,就是在前面方法的基础之上,运用了二分查找。 在使用O(n^2)的方法的时候,查找i前边的比它小或者大的时候,是遍历前面每一个元素,并且进行比较。这样,时间复杂度就为O(n^2)。但是,在实现算法的过程中,在计算第i个元素的时候,前面的元素有哪些最长或者最短的情况,已经知道了,能不能存储这些总监的将诶股,进而加速查找呢?这就是O(nlogn)的算法的根本思想,下面举例说明这个过程:

a

4

2

6

3

1

5

当i=1,dp[1]=1,b[1]=4(最大上升子序列长度为1的序列中元素最小值4)

dp

1

1

1

1

1

1

b

4

当i=2,dp[2]=1,b[1]=2(b[1]原来是4,第二个元素,长度为1,但是更小2<4)

dp

1

1

1

1

1

1

b

2

当i=3,dp[3]=2,b[2]=6

dp

1

1

2

1

1

1

b

2

6

当i=4,dp[4]=3,b[2]=3, 3<6

dp

1

1

2

2

1

1

b

2

3

当i=5,dp[5]=1,b[1]=1,1<2

dp

1

1

2

2

1

1

b

1

3

当i=6,dp[6]=3,d[3]=5

dp

1

1

2

2

1

3

b

1

3

5

上面a是原数组,b[i]存储最大长度为i的序列中的最小值,dp[i]以第i个元素结尾的子序列的最长长度。实现代码如下:
#include 

int n, p, bl, l, r, m;

int a[40001], dp[40001], b[40001];
int main() {
	scanf("%d", &n);
	while (n--) {
		scanf("%d", &p);
		for (int i = 1; i <= p; ++i)
			scanf("%d", &a[i]);
		a[0] = b[0] = dp[0] = bl = m = 0;
		for (int i = 1; i <= p; ++i) {
			l = 1;
			r = bl;
			while (l <= r) {
				int mid = (l + r) / 2;
				if (b[mid] < a[i])
					l = mid + 1;
				else
					r = mid - 1;
			}
			dp[i] = l;
			b[l] = a[i];
			if (bl < l)
				bl = l;
			if (dp[i] > m)
				m = dp[i];
		}
		printf("%d\n", m);
	}
	return 0;
}

  在第一遍实现的过程中,我用的是cin和cout还是TLE了。后来改成scanf和printf,就顺利通过了,而且,我将前面的两道题目,都使用如上的方法实现了一遍,使用cin是15ms,使用scanf是0ms。所以:
还是要多多使用scanf和printf,而不是cin和cout。

posted on 2012-02-05 10:27  sing1ee  阅读(291)  评论(0)    收藏  举报