UVa 10534 Wavio Sequence(LIS N*logN)
题意:
找一个最长(假设长度为2N-1)的子序列,使得前N个元素递增,后N个元素递减。
思路:
LIS。从1-n遍历求出最长上升子序列,再从n-1遍历求出逆序的最长上升子序列。
用最朴素的LIS算法是O(n*n),这一题就tle了。于是网上搜索出来一种O(nlogn)的算法。
http://www.slyar.com/blog/longest-ordered-subsequence.html
大致思路就是:开辟一个堆栈,栈里面的元素是递增的。如果a[i]比栈顶元素要大,就直接压栈。
如果比栈顶元素小,则从底部起找到第一个不比a[i]小的元素替换之。
#include <cstdio> #include <cstdlib> #include <cstring> #include <climits> #define max(a,b) (((a) > (b)) ? (a) : (b)) #define min(a,b) (((a) < (b)) ? (a) : (b)) const int MAXN = 10010; int stack[MAXN]; int d1[MAXN], d2[MAXN]; int a[MAXN]; int main() { int n; while (scanf("%d", &n) != EOF) { for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); int top = 0; stack[0] = INT_MIN; for (int i = 1; i <= n; ++i) { if (a[i] > stack[top]) stack[++top] = a[i]; else { int low = 1, high = top; while (low <= high) { int mid = (low + high) >> 1; if (a[i] > stack[mid]) low = mid + 1; else high = mid - 1; } stack[low] = a[i]; } d1[i] = top; } top = 0; stack[0] = INT_MIN; for (int i = n; i >= 1; --i) { if (a[i] > stack[top]) stack[++top] = a[i]; else { int low = 1, high = top; while (low <= high) { int mid = (low + high) >> 1; if (a[i] > stack[mid]) low = mid + 1; else high = mid - 1; } stack[low] = a[i]; } d2[i] = top; } int ans = 0; for (int i = 1; i <= n; ++i) if (ans < min(d1[i], d2[i])) ans = min(d1[i], d2[i]); printf("%d\n", 2 * ans - 1); } return 0; }
-------------------------------------------------------
kedebug
Department of Computer Science and Engineering,
Shanghai Jiao Tong University
E-mail: kedebug0@gmail.com
GitHub: http://github.com/kedebug
-------------------------------------------------------