UVA

来源:互联网 发布:淘宝漫画图 编辑:程序博客网 时间:2024/06/05 21:04

题意:给定一个长度为n的整数序列a,求一个最长子序列,使得该序列的长度为2*k+1,前k+1个数严格递增,后k+1个数严格递减。

思路:用二分法求最长上升子序列。问题转化为求以i结尾的最长上升子序列和以i开始的最长递减子序列,而以i开始的最长递减子序列可以看作从n开始以i结尾的最长上升子序列。用dp[i]表示长度为i的子序列尾部元素的最小值,显然dp[i]为递增的,那么就可以二分查找了。用num[i]表示以a[i]结尾的最长子序列的长度。先从1-n求一遍num1[i],在从n-1求一遍num2[i],则答案为max(2 * min(num1[i], num2[i]) + 1);

从dp数组找第一个大于a[i]的数dp[t],用a[i]替换,则t就为num[i]。

#include <cstdio>#include <algorithm>#include <iostream>#include<vector>#include<cmath>#include<set>#include<cstring>#include<map>using namespace std;typedef long long ll;const int maxn = 21e2 + 10;const int maxt = 100200;const int inf = 0x3f3f3f3f;const ll INF = 0x7f7f7f7f7f;const int mod = 1e9 + 7;const double pi = acos(-1.0);const double eps = 1e-8;int a[10010], b[10010];int num1[10010], num2[10010];int dp1[10010], dp2[10010];int n;int main(){    while(~scanf("%d", &n)){        for(int i = 0; i < n; ++i){            scanf("%d", &a[i]);            b[n - i - 1] = a[i];        }        memset(dp1, inf, sizeof dp1);        memset(dp2, inf, sizeof dp2);        for(int i = 0; i < n; ++i){            int t1 = lower_bound(dp1, dp1 + n, a[i]) - dp1;            num1[i] = t1;            dp1[t1] = a[i];            int t2 = lower_bound(dp2, dp2 + n, b[i]) - dp2;            num2[i] = t2;            dp2[t2] = b[i];        }        int ans = 1;        for(int i = 0; i < n; ++i){            ans = max(ans, 2 * min(num1[i], num2[n - i - 1]) + 1);        }        printf("%d\n", ans);    }    return 0;}


1 0
原创粉丝点击