uva10534 - Wavio Sequence O(nlgn)的最长上升子序列

  以前也遇到过用正常方法O(n^2)超时的的情况,然后就听说有O(nlgn)的方法,查了一下觉得好麻烦就没看。。果然今天又遇见了超时=。= 没办法了 就看了一下这个算法。交了之后3s超时变成了0.172s过~ 没想到差这么大 ~

  原来O(n^2)的是用了2重循环,现在这个变成了1个循环+二分,二分时间复杂度是O(lgn),所以成了O(nlgn)。那怎么实现这个算法呢?

  方法一:

  我们要用一个栈s,s[i]保存当前最长上升子序列长度为i+1并且最后一个元素最小的最后一个元素的位置=。= 这句话我自己都觉得绕。。初始化的时候top=0,s[0]=0,dp[0]=1(dp[i]表示a[i]作为最后一个元素最长上升子序列长度,s[0]=0是因为目前只有a[0],长度是1,最后一个元素编号是0),i从第二个元素循环到最后一个元素,如果a[i]>a[s[top]],则把i入栈,dp[i]=dp[s[top]]+1。如果a[i]<=a[s[top]],就在栈中找一个位置x,使a[s[x]]是大于等于a[i]的最小值,也就是lower_bound,这里就用二分实现。dp[i]就等于dp[s[x]],这时要把s[x]的值换成i,因为a[i]<=a[s[x]],换了之后后面的元素只要比a[i]大而不一定非要比a[s[x]]大就可以使dp等于原来s[x]代表的长度+1,也就是能使序列尽可能长。

  举个例子 1 2 6 10 5 6 ,前4个元素入栈后,top=3,此时s中元素分别为 0 1 2 3,发现5比a[s[top]]=10小,调用二分lower_bound,得到位置为2,(a[s[2]]=6,是在s中编号的元素中大于等于5的最小的),所以dp[4]=dp[s[2]]=dp[2],此时用4替代s[2],s变成 0 1 4 3,到第6个元素a[5]=6,小于a[s[top]],同样的方法这时得到的位置是3了,现在a[s[2]]=5了,a[s[3]]=10才是大于等于6的最小值,所以dp[5]=dp[s[3]],再用5替代s[3],s变成 0 1 4 5(表示长度为1的最小可以以a[0]结尾,长度为2的最小可以以a[1]结尾,长度为3的最小可以以a[4]结尾,长度为4的最小可以以a[5]结尾)


  方法二:

  还是用这个s,而s[i]保存当前最长上升子序列长度为i+1并且最后一个元素最小的最后一个元素的值。思想是一样的,代码稍微有改动,手写这两种方法的lowerbound也不一样,我觉得这个方法比上面的简单,由于s里存的已经是值,就可以直接调用STL里的lower_bound函数,注意lower_bound是前闭后开的区间,返回的是地址,要再减去首地址。


Problem D
Wavio Sequence
Input:
StandardInput

Output: Standard Output

Time Limit: 2 Seconds

 

Wavio is a sequence of integers. It has some interestingproperties.

·  Wavio is of odd length i.e. L = 2*n+ 1.

·  The first (n+1) integers ofWavio sequence makes a strictly increasing sequence.

·  The last (n+1) integers of Waviosequence makes a strictly decreasing sequence.

·  No two adjacent integers are same in aWavio sequence.

For example 1, 2, 3, 4, 5, 4, 3, 2, 0 is an Waviosequence of length9. But1, 2, 3, 4, 5, 4, 3, 2, 2 is not avalid wavio sequence. In this problem, you will be given a sequence ofintegers. You have to find out the length of the longest Wavio sequence whichis a subsequence of the given sequence. Consider, the given sequence as :

1 2 3 2 1 2 3 4 32 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 outputwill be9.

 

Input

The input filecontains less than 75 test cases. The description of each test case isgiven below: Input is terminated by end of file.

 

Each set starts with a postiveinteger, N(1<=N<=10000). In next few lines there will beNintegers.

 

Output

For each set of input print the length of longest waviosequence in a line.

Sample Input                                  Output for 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
 
9
9
1

 


  方法一:

#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;
int a[10010],s[10010];
int dp1[10010],dp2[10010];

int lowerbound(int x,int y,int v){
    while(x<y){
        int m=(y+x)/2;
        if(a[s[m]]>=v) y=m;
        else x=m+1;
    }
    return x;
}
int main(){
    freopen("in.txt","r",stdin);
    int N;
    while(scanf("%d",&N)!=EOF){
        int i,j,top;
        for(i=0;i<N;i++){
            scanf("%d",&a[i]);
            dp1[i]=dp2[i]=1;
        }
        top=0;
        s[0]=0;
        for(i=1;i<N;i++)      //正向
        if(a[i]>a[s[top]]){
            s[++top]=i;
            dp1[i]=dp1[s[top-1]]+1;
        }
        else{
            int p=lowerbound(0,top+1,a[i]);
            dp1[i]=dp1[s[p]];
            s[p]=i;
        }
        top=0;
        s[0]=N-1;
        for(i=N-2;i>=0;i--)   //反向
        if(a[i]>a[s[top]]){
            s[++top]=i;
            dp2[i]=dp2[s[top-1]]+1;
        }
        else{
            int p=lowerbound(0,top+1,a[i]);
            dp2[i]=dp2[s[p]];
            s[p]=i;
        }
        int ans=0;
        for(i=0;i<N;i++) if(min(dp1[i],dp2[i])*2-1>ans) ans=min(dp1[i],dp2[i])*2-1;
        printf("%d\n",ans);
    }
    return 0;
}

  方法二:

    #include<cstring>
    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #define INF 0x3f3f3f3f
    using namespace std;
    int a[10010],s[10010];
    int dp1[10010],dp2[10010];

    int lowerbound(int x,int y,int v){
        while(x<y){
            int m=(y+x)/2;
            if(s[m]>=v) y=m;
            else x=m+1;
        }
        return x;
    }
    int main(){
        freopen("in.txt","r",stdin);
        int N;
        while(scanf("%d",&N)!=EOF){
            int i,j,top;
            for(i=0;i<N;i++){
                scanf("%d",&a[i]);
                dp1[i]=dp2[i]=1;
            }
            top=0;
            s[0]=a[0];
            for(i=1;i<N;i++)      //正向
            if(a[i]>s[top]){
                s[++top]=a[i];
                dp1[i]=top+1;
            }
            else{
                int p=lower_bound(s,s+top,a[i])-s;
                dp1[i]=p+1;
                s[p]=a[i];
            }
            top=0;
            s[0]=a[N-1];
            for(i=N-2;i>=0;i--)   //反向
            if(a[i]>s[top]){
                s[++top]=a[i];
                dp2[i]=top+1;
            }
            else{
                int p=lower_bound(s,s+top,a[i])-s;
                dp2[i]=p+1;
                s[p]=a[i];
            }
            int ans=0;
            for(i=0;i<N;i++) if(min(dp1[i],dp2[i])*2-1>ans) ans=min(dp1[i],dp2[i])*2-1;
            printf("%d\n",ans);
        }
        return 0;
    }


  在网上看的STL里lower_bound的示例,还不怎么会vector,先留着到时再看~

    #include <iostream>
    #include <algorithm>
    #include <functional>
    #include <vector>

    using namespace std;


    int main()
    {
        const int VECTOR_SIZE = 8 ;

        // Define a template class vector of int
        typedef vector<int > IntVector ;

        //Define an iterator for template class vector of strings
        typedef IntVector::iterator IntVectorIt ;

        IntVector Numbers(VECTOR_SIZE) ;

        IntVectorIt start, end, it, location ;

        // Initialize vector Numbers
        Numbers[0] = 4 ;
        Numbers[1] = 10;
        Numbers[2] = 11 ;
        Numbers[3] = 30 ;
        Numbers[4] = 69 ;
        Numbers[5] = 70 ;
        Numbers[6] = 96 ;
        Numbers[7] = 100;

        start = Numbers.begin() ;   // location of first
                                    // element of Numbers

        end = Numbers.end() ;       // one past the location
                                    // last element of Numbers

        // print content of Numbers
        cout << "Numbers { " ;
        for(it = start; it != end; it++)
            cout << *it << " " ;
        cout << " }\n" << endl ;

        // return the first location at which 10 can be inserted
        // in Numbers
        location = lower_bound(start, end, 1) ;

        cout << "First location element 10 can be inserted in Numbers is: "
            << location - start<< endl ;
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值