uva10524

来源:互联网 发布:人文社科书籍推荐 知乎 编辑:程序博客网 时间:2024/06/06 01:46

题目大意:
找一个最长(假设长度为2N-1)的子序列,使得前N个元素递增,后N个元素递减。

思路:
刚开始没有看到数据可以达到10000 用了求最长递增子序列的方法。。超时了。。
参考了别人的代码。
用一个栈保存子序列的值,从栈顶为最大的数。
如果当前的数大于栈顶的数字的话,那么就把该数压入栈中。
如果当前的数等于栈顶的数字的话,那么不压入栈中,最长递增子序列的值跟栈顶是一样的。
如果当前的数小于栈顶的数字的话,那么找出在栈中恰好比它大的数字。替换这个数字,该数字最长递增子序列的值跟恰好比它大的数字是一样的。
为什么要替换这个数字呢?这样可以让子序列的长度更长。
替换不是插入。因为这样会无法保证 i < j 且a[i] < a[j]。
例如 : 1 2 3 4 5 4 3 2 1 10
到第二个4的时候,它找到恰好大于它的数字是4。那么它递增子序列的值为跟第一个4一样是4。
如果是插入4的话,那么i > j ,a[i] < a[j]的情况就出现了。
代码:

#include <iostream>using namespace std;#include <stdio.h>#include <cstring>const int N = 10005; int a[N],cnt1[N],cnt2[N],stack[N];int fun(int a,int &cnt) {    if(cnt == 0 || stack[cnt] < a) stack[++cnt] = a;    else {        int pos = lower_bound(stack,stack + cnt,a) - stack;        stack[pos] = a;    }    return cnt;}int main() {    int n;    int cnt;    while(scanf("%d",&n) != EOF) {        cnt = 0;        memset(cnt1,0,sizeof(cnt1));        memset(cnt2,0,sizeof(cnt2));        memset(stack,0,sizeof(stack));        for(int i = 0; i < n; i++) {            scanf("%d",&a[i]);            cnt1[i] = fun(a[i],cnt);        }        cnt = 0;        for(int i = n - 1; i >= 0; i--)            cnt2[i] = fun(a[i],cnt);        int _max = 0;        for(int i = 0; i < n; i++)            _max = max(_max,min(cnt1[i],cnt2[i]));        printf("%d\n",_max * 2 - 1);    }    return 0;}
0 0
原创粉丝点击