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