POJ 1631 Bridging signals [最长上升子序列O(nlog(n))]
描述:要为电路板搭线,要求不能交叉,如图,左边的线柱按升序排好,只需在右边线柱中找最长上升子序列。需要用二分优化。
思路:在O(n*n)算法的基础上,加入一个辅助数组best[],下标表示子序列长度,对应值表示所有该长度的序列中的最小头儿,
维护这个数组,更新数组。对于新增的数x,找到位置k,使best[k-1]<x ,且best[k]>x,则best[k] = x。设best[]数组长度是sol
,可以特殊处理best[0],和best[sol-1]的情况,会发现,只有当x > best[sol-1],才会导致sol的增长。易知此序列是有序的,二分的加入就是为了找到位置k。
代码
#include <stdio.h>
#include <string.h>
#define NL 40000
int best[NL];
int main()
{
int n, i, j, x, sol;
int T;
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
scanf("%d", &best[0]);
sol = 1;
for (i=1; i<n; i++) {
scanf("%d", &x);
if (x < best[0]) {
best[0] = x;
continue;
}
if (x > best[sol-1]) {
best[sol++] = x;
continue;
}
int low = 0, high = sol-1, mid, ans;
while (low <= high) {
mid = (low+high)/2;
if (best[mid] < x) {
low = mid + 1;
}else {
high = mid - 1;
ans = mid;
}
}
best[ans] = x;
}
printf("%d\n", sol);
}
return 0;
}