T^T OJ 1388 最长上升子序列

长上升子序列

TimeLimit:1000MS  MemoryLimit:64MB
64-bit integer IO format:%lld
已解决 | 点击收藏 | 已有4人收藏了本题
Problem Description

如果一个数列ai 满足 a1 < a2 < ... < aN 则这个数列被称作上升序列。

给定一个数列a(a1a2, ..., aN)则任意一个数列b(ai1ai2, ..., aiK)并且满足(1 <= i1 < i2 < ... < iK <= N).则b被称为a的子序列。

如果一个数列的子序列是上升序列,则这个序列称为原序列的上升子序列。

 

比如序列(1, 7, 3, 5, 9, 4, 8)的上升子序列有(1, 7), (3, 4, 8)等. 它的最长上升子序列长度是4,即(1, 3, 5, 8).

请你写一个程序求一个序列的最长上升子序列的长度。

Input

第一行是一个整数N表示给定数列的长度. 第二行包括N个范围在0~10000的整数。 1 <= N <= 1000

Output

输出一个整数表示最长上升子序列的最大长度

SampleInput
7
1 7 3 5 9 4 8
SampleOutput
4
 
【思路】:
复杂度为O(n*log(2)(n))的优化版本
就是说,我每次在dp中查找比a【i】小的数字然后,
去替换它,不断更新一个数组。。。。
#include<stdio.h>
#include<algorithm>
using namespace std;
const int inf=1e9+7;
int dp[41111];///dp[i]   最长上升子序列长度为i的时候   最小的尾数
int a[41111];
///dp[pos]<=a[i]长度为pos的时候,最后一个数是<=a[i]
///dp[pos+1]=min(dp[pos+1],a[i])
///dp[i]=MAX(dp[j]+1)   j<i   a[j]<a[i];
///O(n^2)->O(n*log(n))
int efind(int s,int t,int x){
    int l=s-1,r=t+1;
    while(l+1<r){
        int mid=(l+r)/2;
        if(dp[mid]<=x)
            l=mid;
        else r=mid;
    }
    return l;
}///找出第一个小于等于x的位置
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",a+i);
        dp[1]=a[1];
        int top=1;
        for(int i=2;i<=n;i++){
            int pos=efind(1,top,a[i]);
            if(pos==top){
                top++;
                dp[top]=a[i];
            }else{
                dp[pos+1]=min(dp[pos+1],a[i]);
            }
        }
        printf("%d\n",top);
    }
    return 0;
}

 

 
posted @ 2018-05-17 19:17  moxin0509  阅读(148)  评论(0编辑  收藏  举报