例子如4,1,6,2,8,5,7,3
8个数,如何求其最长上升子序列呢。
可以用L[i]表示前面子序列长度为i+1(因为length的下标从0开始)尾元素的最小值。
A[i]装的是每个元素的值。
length=1;
初始化L[0]=A[0].
for i=0 to n-1
if|(L[length-1]<A[I])
L[length++]=A[i];//表明最长的子序列的尾元素小于A[I],那么就可以更新这个尾元素,并且最长子序列长度++
else //说明这个数小于尾元素
for(j=0,1,2,length-1)到length-1是因为L[length-1]就 为目前最长子序列的尾元素
L数组一定为递增顺序,因为添加时候一定比之前的L[length-1]大才能添加新的length
找到第一个大于A[i]的元素,将其L[j]=A[i]后break即可。(仔细想想)这么更新是为了这个长度的尾元素只要最小的那一个,但只能更新一个。
二分的重点:找满足某条件的最大/最小值该怎么二分。
#include<iostream> #include <stdio.h> #include <string.h> #include <set> #include <vector> #include <stdlib.h> #include<direct.h> #include <io.h> #include <direct.h> using namespace std; int L[500]; int A[500]; int main(){ freopen("in.txt","r",stdin); int i,j,k,f1,f2,f3,t1,t2,t3,n,m,T,t; cin >> n; for(i=0;i<n;i++) cin >> A[i]; memset(L,0,sizeof(L)); L[0]=A[0]; int length=1; for(i=1;i<n;i++) if(L[length-1]<A[i]){ L[length++]=A[i]; cout << length <<" " << i<< endl; }else{ int left1,right1,mid1,min1; min1=1e9+7; left1=0;right1=length-1;//从0更新到length-1 while(right1>=left1){ mid1=(right1+left1)/2; if(L[mid1]<=A[i]) left1=mid1+1; else{ right1=mid1-1; min1=min(mid1,min1); } } L[min1]=A[i]; } cout << length << endl; return 0; }