UVALive_4976
这个题目可以先预处理出每个点向左走一共有多少个连续下降的元素,以及向右走一共有多少个连续上升的元素,处理出这两个东西后思路基本就有了。
接下来用线段树也可以做,或者可以借鉴O(NlogN)求解最长上升子序列的方法的思想来做,但后者效率更高一些。
#include<stdio.h> #include<string.h> #include<algorithm> #define MAXD 200010 int N, a[MAXD], s[MAXD], R[MAXD], top; void init() { int i; scanf("%d", &N); for(i = 1; i <= N; i ++) scanf("%d", &a[i]); for(R[N] = 1, i = N - 1; i >= 1; i --) R[i] = a[i] < a[i + 1] ? R[i + 1] + 1 : 1; } int BS(int h) { int mid, min = 0, max = top + 1; for(;;) { mid = min + max >> 1; if(mid == min) break; if(s[mid] < h) min = mid; else max = mid; } return mid; } void solve() { int i, k, x = 1, ans = 1; top = 0, s[++ top] = a[1]; for(i = 2; i <= N; i ++) { ans = std::max(ans, BS(a[i]) + R[i]); a[i] > a[i - 1] ? ++ x : x = 1; if(x > top) s[++ top] = a[i]; else s[x] = std::min(s[x], a[i]); } printf("%d\n", ans); } int main() { int t; scanf("%d", &t); while(t --) { init(); solve(); } return 0; }