uvaoj 10534 Wavio Sequence 最长上升子序列(LIS)

给定一个正整数的序列,求出一个长度为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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值