先回顾经典的O(n^2)的动态规划算法,设A[t]表示序列中的第t个数,F[t]表示从1到t这一段中以t结尾的最长上升子序列的长度,初始时设F[t] = 0(t = 1, 2, ..., len(A))。则有动态规划方程:F[t] = max{1, F[j] + 1} (j = 1, 2, ..., t - 1, 且A[j] < A[t])。
注意到D[]的两个特点:
(1) D[k]的值是在整个计算过程中是单调不上升的。
(2) D[]的值是有序的,即D[1] < D[2] < D[3] < ... < D[n]。
利用D[],我们可以得到另外一种计算最长上升子序列长度的方法。设当前已经求出的最长上升子序列长度为len。先判断A[t]与D[len]。若A[t] > D[len],则将A[t]接在D[len]后将得到一个更长的上升子序列,len = len + 1, D[len] = A[t];否则,在D[1]..D[len]中,找到最大的j,满足D[j] < A[t]。令k = j + 1,则有D[j] < A[t] <= D[k],将A[t]接在D[j]后将得到一个更长的上升子序列,同时更新D[k] = A[t]。最后,len即为所要求的最长上升子序列的长度。
poj 3903
</pre><pre name="code" class="cpp">#define MAX 100000
#define INF 100000000
int a[MAX],c[MAX],len;
int find(int L,int R,int x)
{
if(L==R) return L;
int mid=(L+R)>>1;
if(c[mid]<x) return find(mid+1,len,x);
else return find(L,mid,x);
}
int main()
{
int i,n,t,m,T,b,k,ans,j,max;
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<n;i++)
scanf("%d",&a[i]);
len=0; c[0]=-INF;
for(i=0;i<n;i++)
{
if(a[i]>c[len]) j=++len;
else j=find(1,len,a[i]);
c[j]=a[i];
}
printf("%d\n",len);
}
}