hihocoder_offer收割编程练习赛53_3 最长一次上升子序列
题目链接: https://hihocoder.com/contest/offers53/problem/3
解题思路: 最长一次上升子序列,必然是一个先下降,然后上升一次,然后接着下降的序列。这就把原问题分解成两个子问题,求1--i的最长下降子序列,和i到n-1的最长下降子序列,然后拼起来求一个最大值。还有一个特殊的情况,所有的序列都是下降的,此时就是整个序列的长度。
#include <bits/stdc++.h> using namespace std; const int imax_n = 100005; int a[imax_n]; int b[imax_n]; int da[imax_n]; int db[imax_n]; int pb[imax_n]; int n; int x[imax_n]; int cnt; int b_search(int x[], int n, int k) { int l = 0; int r = n - 1; while (l <= r) { int mid = l + (r - l) / 2; // printf("l=%d, r=%d, a[mid] = %d, k = %d\n", l, r, x[mid], k); if (x[mid] <= k) { l = mid + 1; } else { r = mid - 1; } } return l; } void findLongestIns(int a[], int da[], int n) { da[0] = 1; cnt = 0; x[cnt++] = a[0]; for (int i = 1; i < n; ++i) { int pos = b_search(x, cnt, a[i]); da[i] = pos + 1; if (pos == cnt) { x[cnt++] = a[i]; } else if (a[i] < x[pos]) { x[pos] = a[i]; } } } int p_search(int x[], int n, int k) { int l = 0; int r = n-1; while (l <= r) { int mid = l + (r - l) / 2; if (x[mid] >= k) { l = mid + 1; } else { r = mid - 1; } } return l; } void findLongestDes(int a[], int da[], int n) { da[0] = 1; cnt = 0; x[cnt++] = a[0]; for (int i = 1; i < n ; ++i) { int pos = p_search(x, cnt, a[i]); da[i] = pos + 1; if (pos == cnt) { x[cnt++] = a[i]; } else if (a[i] > x[pos]) { x[pos] = a[i]; } } } int main() { scanf("%d", &n); for (int i = 0; i < n; ++i) { scanf("%d", &a[i]); b[n - i - 1] = a[i]; } findLongestDes(a, da, n); // for (int i = 0; i < n; ++i) // { // printf("%d ", da[i]); // } // printf("\n"); findLongestIns(b, db, n); // for (int i = n-1; i >=0; i--) // { // printf("%d ", db[i]); // } // printf("\n"); pb[0] = db[0]; for (int i = 1; i < n; ++i) { pb[i] = max(pb[i-1], db[i]); } // for (int i = 0; i < n; ++i) // { // printf("%d ", pb[i]); // } // printf("\n"); int ans = 0; for (int i = 1; i < n; ++i) { ans = max(ans, da[i-1] + pb[n - i - 1]); } ans = max(ans, db[0]); printf("%d\n", ans); return 0; } /* test 5 5 4 3 2 1 5 1 2 3 4 5 */