给定一个正整数的序列,求出一个长度为2*n+1的序列,使得前n+1个数严格递增,后n+1个数严格递减,求使这个序列的长度最长是多少。
设给定的序列为n个数,记为num[1...n],如果我们求得了以num[i]结尾的最长上升子序列的长度(记为dp1[i])和以num[i]开始的最长下降子序列的长度(记为dp2[i]),那么以num[i]为中心的符合要求的序列长度就是2*min(dp1[i], dp2[i])-1;这样我们遍历一边就可以求出最长的序列的长度了。
使用最长上升子序列的nlogn算法,在计算的过程中记录相应的值,就可以了。要注意的是,最长下降子序列可以转化成最长上升子序列,即将原串逆序即可。
代码如下:
/*************************************************************************
> File Name: 10534.cpp
> Author: gwq
> Mail: gwq5210@qq.com
> Created Time: 2014年12月22日 星期一 16时03分33秒
************************************************************************/
#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>
#define INF (INT_MAX / 10)
#define clr(arr, val) memset(arr, val, sizeof(arr))
#define pb push_back
#define sz(a) ((int)(a).size())
using namespace std;
typedef set<int> si;
typedef vector<int> vi;
typedef map<int, int> mii;
typedef long long ll;
const double esp = 1e-5;
#define N 10010
// dp1[i]记录以num[i]结尾的最长上升子序列的长度
// dp2[i]记录以num[i]开头的最长下降子序列的长度
// 需要注意的是将原来逆序求最长上升子序列就相当于求最长下降子序列
int dp1[N], dp2[N], num[N], n, t1[N], t2[N];
void lis(int dp[], int t[])
{
dp[0] = 1;
t[1] = num[0];
int len = 1;
//printf("1 ");
for (int i = 1; i < n; ++i) {
// 求的过程中记录下来num[i]的最长上升子序列的长度
if (num[i] > t[len]) {
t[++len] = num[i];
dp[i] = len;
} else {
int l = 1;
int r = len - 1;
int pos = 1;
while (l <= r) {
int mid = (l + r) / 2;
if (t[mid] < num[i] && t[mid + 1] >= num[i]) {
pos = mid + 1;
break;
} else if (t[mid] < num[i]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
//printf(".%d..%d...\n", i, pos);
t[pos] = num[i];
dp[i] = pos;
}
//printf("%d ", dp[i]);
}
//printf("\n");
}
int main(int argc, char *argv[])
{
while (scanf("%d", &n) != EOF) {
for (int i = 0; i < n; ++i) {
scanf("%d", &num[i]);
}
clr(t2, 0);
clr(dp2, 0);
lis(dp1, t1);
reverse(num, num + n);
lis(dp2, t2);
reverse(dp2, dp2 + n);
int res = 0;
for (int i = 0; i < n; ++i) {
res = max(res, 2 * min(dp1[i], dp2[i]) - 1);
}
printf("%d\n", res);
}
return 0;
}