首页 > 技术文章 > nyoj 214——单调递增子序列(二)——————【二分搜索加dp】

chengsheng 2015-05-15 09:27 原文

单调递增子序列(二)

时间限制: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
*/

  







推荐阅读