题意:在一个数字序列中找到最长的一个子序列,从数字上升到下降的长度最长,而且上升长度和下降长度相等,输出这个长度。
题解:直接用普通的0(n^2)的方法会超时,上网找了用O(nlogn)的方法理解了一下,加了一个c[N]数组,存的是当前最长上升子序列,如果是O(N^2)的做法会是遍历一遍从0到i的值然后更新最长上升子序列的长度,但是有了c数组可以直接根据此时的最长上升子序列更新f[i]的值,二分查找使时间复杂度降到n*logn。
#include <stdio.h>
#include <string.h>
const int N = 10005;
int n, s[N], f1[N], f2[N], c[N], d[N];
int search(int i, int *a) {
int left = 0, right = n + 1, mid = (left + right) / 2;
while (left < right) {
if (s[i] > a[mid])
left = mid + 1;
else
right = mid;
mid = (left + right) / 2;
}
return right;
}
int main() {
while (scanf("%d", &n) != EOF) {
for (int i = 0; i < n; i++)
scanf("%d", &s[i]);
for (int i = 0; i <= n; i++)
c[i] = d[i] = 0x3f3f3f3f;
f1[0] = f2[n - 1] = 1;
c[0] = d[0] = -1;
c[1] = s[0];
d[1] = s[n - 1];
for (int i = 1; i < n; i++) {
int j = search(i, c);
c[j] = s[i];
f1[i] = j;
}
for (int i = n - 2; i >= 0; i--) {
int j = search(i, d);
d[j] = s[i];
f2[i] = j;
}
int res = -1, temp;
for (int i = 0; i < n; i++) {
temp = f1[i] > f2[i] ? f2[i] : f1[i];
res = res < temp ? temp : res;
}
printf("%d\n", 2 * res - 1);
}
return 0;
}