Wavio Sequence UVA - 10534

最长上升子序列
题目描述:给了一个定义的序列Wavio,该序列的定义是:长度为2*n + 1,前n+1个数是严格递增的,后n+1个数是严格递减的,且相邻两个数不重复。求最长的Wavio序列的长度。
解题分析:数据量是10000,显然n*n的算法行不通,必须得用n*logn的算法。在本题中我的解法是,正序求最长上升子序列,逆序再求一遍,分别记录上升序列的最小下标,算完两个序列后,只要判断两个上升序列没有交差,那这个序列就是Waviox序列,更新最大值即可。在此处不用判断两个上升序列的最大值是否相等,因为如若不等,总可以让其中一个大的上升序列的最大值来替换小的那个上升序列的最大值。例如序列是1 2 4 7 和 9 8 2 1 ,只需要让第一个序列的最大值变为9就可以满足是Wavio序列了,前提是两个序列没有交叉。判断两个序列没有交叉就是判断的这两个序列的最大值的最小下标和是否>= N,如果不,则不交叉。
代码如下:

手写二分查找版

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 10000 + 10;
int num[maxn];
int dp1[maxn];
int dp2[maxn];
int index1[maxn];
int index2[maxn];

int bin_s(int t,int len,int * dp)
{
    int l = 0,r = len + 1;
    int ans;
    while(r - l > 1)
    {
        int mid = (l + r) / 2;
        if(dp[mid] >= t)
        {
            r = mid;
            ans = mid;
        }
        else
        {
            l = mid;
        }
    }
    return ans;
}

int main()
{
    int N;
    while(scanf("%d",&N)!=EOF)
    {
        for(int i = 0; i < N; i++)
        {
            scanf("%d",&num[i]);
        }
        memset(dp1,0x3f,sizeof(dp1));
        memset(dp2,0x3f,sizeof(dp2));
        int len = 1;
        dp1[1] = num[0];
        index1[len] = 0;
        for(int i = 1; i < N; i++)
        {
            if(num[i] > dp1[len])
            {
                dp1[++len] = num[i];
                index1[len] = i;
            }
            else
            {
                int t = bin_s(num[i],len,dp1);
                dp1[t] = num[i];
            }
        }
        reverse(num,num + N);
        len = 1;
        dp2[1] = num[0];
        index2[len] = 0;
        for(int i = 1; i < N; i++)
        {
            if(num[i] > dp2[len])
            {
                dp2[++len] = num[i];
                index2[len] = i;
            }
            else
            {
                int t = bin_s(num[i],len,dp2);
                dp2[t] = num[i];
            }
        }
        int ans = -1;
        for(int i = 1; i <= N; i++)
        {
            if(dp1[i] == INF ||dp2[i] == INF) continue;
            if(index1[i] + index2[i] >= N) continue;
            ans = max(ans,i);
        }
        cout << 2 * ans - 1 << endl;
    }
    return 0;
}

lower_bound版
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 10000 + 10;
int num[maxn];
int dp1[maxn];
int dp2[maxn];
int index1[maxn];
int index2[maxn];

int main()
{
    int N;
    while(scanf("%d",&N)!=EOF)
    {
        for(int i = 0; i < N; i++)
        {
            scanf("%d",&num[i]);
        }
        memset(dp1,0x3f,sizeof(dp1));
        memset(dp2,0x3f,sizeof(dp2));
        for(int i = 0; i < N; i++)
        {
            int t  =  lower_bound(dp1,dp1 + N,num[i]) - dp1;
            if(dp1[t] == INF) index1[t] = i;
            dp1[t] = num[i];
        }
        reverse(num,num + N);
        for(int i = 0; i < N; i++)
        {
            int t  =  lower_bound(dp2,dp2 + N,num[i]) - dp2;
            if(dp2[t] == INF) index2[t] = i;
            dp2[t] = num[i];
        }
        int ans = -1;
        for(int i = 0; i < N; i++)
        {
            if(dp1[i] == INF ||dp2[i] == INF) continue;
            if(index1[i] + index2[i] >= N) continue;
            ans = max(ans,i + 1);
        }
        cout << 2 * ans - 1 << endl;
    }
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值