uva 10534 Wavio Sequence XX序列(第一个词不认识)

原题:
Wavio is a sequence of integers. It has some interesting properties.
• Wavio is of odd length i.e. L = 2 ∗ n + 1.
• The first (n + 1) integers of Wavio sequence makes a strictly increasing sequence.
• The last (n + 1) integers of Wavio sequence makes a strictly decreasing sequence.
• No two adjacent integers are same in a Wavio sequence.
For example 1, 2, 3, 4, 5, 4, 3, 2, 0 is an Wavio sequence of length 9. But 1, 2, 3, 4, 5, 4, 3, 2, 2 is
not a valid wavio sequence. In this problem, you will be given a sequence of integers. You have to find
out the length of the longest Wavio sequence which is a subsequence of the given sequence. Consider,
the given sequence as :
1 2 3 2 1 2 3 4 3 2 1 5 4 1 2 3 2 2 1.
Here the longest Wavio sequence is : 1 2 3 4 5 4 3 2 1. So, the output will be ‘9’.
Input
The input file contains less than 75 test cases. The description of each test case is given below. Input
is terminated by end of file.
Each set starts with a postive integer, N (1 ≤ N ≤ 10000). In next few lines there will be N
integers.
Output
For each set of input print the length of longest wavio sequence in a line.
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
题目大意:
给你n个数,让你找到这样一个2*k+1个数,前k+1个数是严格递增的序列,后k个数是严格单调递减序列。让你找最长的2*k+1是多少?
思路和吐槽见代码下方

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
const int N = 10001;
struct nums
{
    int mark;
    int nu;
};
struct flag
{
    int pos,mark;
};
nums num[N],seq[N],rnum[N];
int dp[N],rdp[N];
int n,ans;
int max(int x,int y)
{
    if(x>y)
    return x;
    return y;
}
int min(int x,int y)
{
    if(x<y)
    return x;
    return y;
}
flag binS(nums key,int len)
{
    flag tem;
    int low=1,hi=len;
    while(low<=hi)
    {
        int mid=(low+hi)>>1;
        if(key.nu>seq[mid].nu&&key.nu<=seq[mid+1].nu)
        {
            tem.mark=seq[mid+1].mark;
            tem.pos=mid+1;
            return tem;
        }
        else
        {
            if(key.nu>seq[mid].nu)
            low=mid+1;
            else
            hi=mid-1;
        }
    }
    tem.mark=1;
    tem.pos=1;
    return tem;
}
void lis()
{
    flag index;
    int i,len=1;
    seq[len].nu=num[1].nu;
    seq[len].mark=1;
    dp[1]=1;
    for(i=2;i<=n;i++)
    {
        if(seq[len].nu<num[i].nu)
        {
            len++;
            seq[len].nu=num[i].nu;
            seq[len].mark=num[i].mark;
            dp[num[i].mark]=len;
        }
        else
        {
            index=binS(num[i],len);//返回的index里面是找到的数在seq的位置和数的编号
            dp[num[i].mark]=dp[index.mark];
            seq[index.pos].nu=num[i].nu;
            seq[index.pos].mark=num[i].mark;
        }
    }
}
int main()
{
    int des,aes,tem;
    ios::sync_with_stdio(false);
    while(cin>>n)
    {
        memset(dp,0,sizeof(dp));
        memset(seq,0,sizeof(seq));
        memset(rdp,0,sizeof(rdp));
        ans=des=aes=0;
        for(int i=1;i<=n;i++)
        {
            cin>>num[i].nu;
            num[i].mark=i;
            rnum[n-i+1].nu=num[i].nu;
            rnum[n-i+1].mark=num[i].mark;
            if(i>1)
            {
                if(num[i].nu-num[i-1].nu>=0)
                aes++;
                else
                des++;
            }
        }
        if(aes==n-1||des==n-1||n==1)//如果是单调增或者单调减或者只有一个值,输出1
        {
            cout<<1<<endl;
            continue;
        }
        lis();
        for(int i=1;i<=n;i++)
        {
            rdp[i]=dp[i];
            num[i].nu=rnum[i].nu;
            num[i].mark=rnum[n-i+1].mark;
        }
        memset(dp,0,sizeof(dp));
        memset(seq,0,sizeof(seq));
        lis();
        for(int i=1;i<=n;i++)
        {
            tem=min(rdp[i],dp[n-i+1]);
            tem=tem*2-1;
            ans=max(ans,tem);
        }
        cout<<ans<<endl;
/*      for(int i=1;i<=n;i++)
        cout<<rdp[i]<<" ";
        cout<<endl;
        for(int i=1;i<=n;i++)
        cout<<dp[i]<<" ";
        cout<<endl;*/
    }
    return 0;
}




思路:
我这代码写的真是又臭又长,不过好歹过了。做这道题的时候uvaoj出毛病了,提交的代码都只显示在判定队列中,过了两天终于等到结果,尼玛超时了~~
先唠唠想法,第一眼看着这题肯定会往最经典的那个动态规划问题,最长递增子序列上想。ok,想到这,这题已经做出20%了,然而并没有什么卵用。既然是让你找先递增后递减的,对称长度的序列,那就把这个序列正向求一次最长递增子序列,然后再反向求一次。结果保存到dp[]和rdp[]当中,dp[i]表示的是以第i个数作为结尾能够找到的最长递增子序列,同理rdp[]。然后枚举原序列中每个数字i,dp[i]代表从左到i最长的递增子序列的长度记为a,rdp[i]代表从右往左到i的最长递增子序列的长度记为b。每次找出a和b两个最小的作为结果保存到tem,相当于找到了结果序列的其中一半(自己动手画一下就明白),然后乘以2再减去1(中间被枚举的数多计了一次)保存到ans,下次再找到min(a,b)的时候判断新tem是否大于ans,如果大,则更新。
如图:
这里写图片描述
就这样,第一次的代码虽然做出来,但是超时了。实在想不出其他的什么办法,但是我知道求最长递增子序列的一个nlogn的算法,所以就打算拿它开刀。这里恶心的地方也出来,nlogn算法里面有两个数组,一个是原来的数列num[],另外一个是seqp[],这个seq里面保存的是一个有序序列,每次新找到的元素都会在这个序列里面二分查找它的位置(百度nlogn最长公共子序列),并没有保存类似dp[i]的东西,所以加个dp[i]用来记录就可以了。比如找到当前的元素i,要求dp[i]的值,先判断这第i个值是不是比i-1个值大,如果是则dp[i]=上一个长度+1(也就是增加后的len),如果不是,那就在seq中二分查找第i个元素的位置,具体查找的是等于num[i]或者是第一大于num[i]的那个数,这个数对应的dp值也就是num[i]对应的dp值。如此下来,两次nlogn的算法就解决了~~
头两次提交没把标准输入输出流关掉,所以速度慢了点。关闭后速度比较快。
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值