ZOJ 1986 最长升序数

////////////////////////////////////
//最长升序数
//用dp+二分法
//若用常规的做法用n^2的时间,用二分以后降为nlogn

 

//    这种二分法很巧妙,先弄一个数组st[],每次读入a[i],找出在st[]中刚比它小的后一位st[k]
//用a[i]替换s[k]。当k小于len时,这种替换不会改变最长链的最大数;当k=len时,最大链最大数
//被改为一个更小的数a[i],不影响之后链的加长,且更容易加长;当k=len+1时,直接加长一位a[i]
//但此方法不能输出最长子序列

#include<iostream>
using namespace std;
unsigned int a[40005];
unsigned int st[40005];


int main()
{
    unsigned int i,n,num,len,left,right,mid;
    cin>>n;
    while(n--)
    {
        cin>>num;
        for(i=0;i<num;i++)
            cin>>a[i];

        st[0]=0;
        st[1]=a[0];
        len=1;
        for(i=1;i<num;i++)
        {
            left=0; right=len;
            while(left<=right)
            {
                mid=(left+right)/2;
                if(st[mid]<=a[i])
                    left=mid+1;           //让left为比a[i]小的后一位k
                else
                    right=mid-1;
            }
            st[left]=a[i];
            if(left>len)
                len++;
        }
        cout<<len<<endl;
    }
    return 0;
}

 

 

 

你可能感兴趣的:(ZOJ)