nyoj 214——单调递增子序列(二)——————【二分搜索加dp】

单调递增子序列(二)

时间限制: 1000 ms  |  内存限制:65535 KB
难度: 4
 
描述

给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度。

如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5。

 
输入
有多组测试数据(<=7)
每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=100000)。
数据以EOF结束 。
输入数据保证合法(全为int型整数)!
输出
对于每组测试数据输出整形数列的最长递增子序列的长度,每个输出占一行。
样例输入
7

1 9 10 5 11 2 13

2

2 -1
样例输出
5

1


解题思路:这个题目看着跟求单调递增子序列(一)只是在数据范围上扩大了,其实在做法上也因此改变了。这个在n*log(n)的时间复杂度内是可以解决的,所以这里用到了一种别样的方式。在数组D中存放当前len值时符合条件的单调递增的子序列,每个D[]都是子序列的一个元素。每次在D中查找比当前输入的原始序列元素值大的最小值位置,返回下标。将该位置更新为输入元素,然后判断是否需要将len值增加。


#include<bits/stdc++.h>

using namespace std;

const int maxn=100100;

const int INF=1e9;

int pos;

int D[maxn];

int BinSearch(int l,int r,int key){

    while(l<=r){

     //   printf("%d %d\n",l,r);

        int mid=(l+r)/2;

        if(D[mid]<key){

            l=mid+1;

        }else if(D[mid]>key){

            r=mid-1;

        }else{

            return l;

        }

    }

    return l;

}

int main(){

    int n,i,j,k;

    while(scanf("%d",&n)!=EOF){

        scanf("%d",&pos);

        int len=1;

        D[0]=pos;

        for(i=1;i<n;i++){

            scanf("%d",&pos);

            j=BinSearch(0,len-1,pos);

    //        printf("%d....\n",j);

            D[j]=pos;

            len=j+1>len?j+1:len;

        }

        printf("%d\n",len);

    }

    return 0;

}

/*

10

2 3 5 7 4 6 8 9 11 12



6

2 3 1 1 6 8



6

8 9 4 5 6 3

*/

  







你可能感兴趣的:(dp)