DP - 最长上升子序列(nlogn模板) - Wavio Sequence - UVA - 10534

DP - 最长上升子序列(nlogn模板) - Wavio Sequence - UVA - 10534

题意:

多 组 测 试 数 据 , 每 组 包 括 一 个 长 度 为 n 的 序 列 。 多组测试数据,每组包括一个长度为n的序列。 n

求 这 个 序 列 中 最 长 的 “ 凸 ” 序 列 的 长 度 。 求这个序列中最长的“凸”序列的长度。

“ 凸 ” 序 列 : 先 严 格 递 增 , 再 严 格 递 减 , 且 递 增 的 长 度 与 递 减 的 长 度 相 同 。 “凸”序列:先严格递增,再严格递减,且递增的长度与递减的长度相同。

举例:

1 2 3 2 1 2 3 4 3 2 1 5 4 1 2 3 2 2 1
the longest Wavio sequence is : 1 2 3 4 5 4 3 2 1

元 素 5 的 左 侧 严 格 递 增 的 长 度 为 5 , 右 侧 严 格 递 减 的 长 度 为 5 , 总 长 度 为 2 × 5 − 1 = 9 。 元素5的左侧严格递增的长度为5,右侧严格递减的长度为5,总长度为2×5-1=9。 5552×51=9

Sample Input:
10
1 2 3 4 5 4 3 2 1 10
19
1 2 3 2 1 2 3 4 3 2 1 5 4 1 2 3 2 2 1
5
1 2 3 4 5

Sample Output:
9
9
1

数据范围:

1 < = n < = 10000 T i m e   l i m i t : 3000   m s 1<=n<=10000\\Time\ limit:3000 \ ms 1<=n<=10000Time limit3000 ms


分析:

与——《DP - 最长上升子序列模型 - NOIP2004提高组 - 合唱队形 + 北京大学ACM/ICPC选拔赛 - 登山》类似。

区 别 在 于 : 本 题 要 求 中 心 两 侧 单 调 的 序 列 长 度 相 同 。 区别在于:本题要求中心两侧单调的序列长度相同。

那 么 与 上 述 模 型 类 似 的 , 正 反 两 遍 做 最 长 上 升 子 序 列 后 , 对 中 心 i , 要 取 i 左 侧 严 格 递 增 序 列 长 度 与 右 侧 严 格 递 减 序 列 长 度 的 较 小 值 r e s 。 最 终 结 果 应 当 是 2 × r e s − 1 。 那么与上述模型类似的,正反两遍做最长上升子序列后,\\对中心i,要取i左侧严格递增序列长度与右侧严格递减序列长度的较小值res。\\最终结果应当是2×res-1。 iires2×res1

需要注意的是:

本 题 数 据 范 围 是 10000 , 因 此 O ( n 2 ) 的 朴 素 写 法 被 卡 掉 了 , 要 用 单 调 队 列 + 二 分 优 化 。 本题数据范围是10000,因此O(n^2)的朴素写法被卡掉了,要用单调队列+二分优化。 10000O(n2)+

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>

#define ll long long
#define inf 0x3f3f3f3f

using namespace std;

const int N=10010;

int n,a[N],f1[N],f2[N];

int main()
{
    while(~scanf("%d",&n))
    {
        memset(f1,0,sizeof f1);
        memset(f2,0,sizeof f2);

        for(int i=1;i<=n;i++) scanf("%d",&a[i]);

        int q[N];
        q[0]=-1e9;int len=0;
        for(int i=1;i<=n;i++)
        {
            int l=0,r=len;
            while(l<r)
            {
                int mid=l+r+1>>1;
                if(q[mid]<a[i]) l=mid;
                else r=mid-1;
            }
            len=max(len,r+1);
            f1[i]=r+1;
            q[r+1]=a[i];
        }

        memset(q,0,sizeof q);
        q[0]=-1e9;len=0;
        for(int i=n;i;i--)
        {
            int l=0,r=len;
            while(l<r)
            {
                int mid=l+r+1>>1;
                if(q[mid]<a[i]) l=mid;
                else r=mid-1;
            }
            len=max(len,r+1);
            f2[i]=r+1;
            q[r+1]=a[i];
        }

        int res=1;
        for(int i=1;i<=n;i++) res=max(res,min(f1[i],f2[i]));

        printf("%d\n",2*res-1);
    }

    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值