最长上升子序列
摘自《挑战程序设计竞赛》如有错误,请指正!
(1)
定义:dp[ i ]表示以Ai为末尾的最长上升子序列。
以Ai结尾的上升子序列是:①只包含Ai的子序列②再满足 j < i 并且Aj < Ai 的以Aj为结尾的子序列,追加上Ai后得到的子序列。
于是,dp[ i ]=max(1,dp[ j ]+1 | j<i and aj<ai)。
复杂度O(n²)
1 int n; 2 int a[maxn],dp[maxn]; 3 4 void sovle(){ 5 int res=0; 6 for(int i=0;i<n;i++){ 7 dp[i]=1; 8 for(int j=0;j<i;j++) if(a[j]<a[i]) dp[i]=max(dp[i],dp[j]+1); 9 res=max(res,dp[i]); 10 } 11 cout<<res<<endl; 12 } 13
(2)
前面我们用DP求取针对最末尾的元素的最长的子序列。如果子序列的长度相同,那么最末尾的元素较小的在之后会更加有优势,所以我们反过来用DP针对
相同长度情况下最小的末尾元素进行求解。
定义:dp[ i ]表示长度为i+1的上升子序列中末尾元素的最小值(不存在的话就INF)。
复杂度O(nlogn)
1 int n; 2 int a[maxn],dp[maxn]; 3 4 void sovle(){ 5 fill(dp,dp+n,INF); 6 for(int i=0;i<n;i++) *lower_bound(dp,dp+n,a[i])=a[i]; 7 int ans=lower_bound(dp,dp+n,INF)-dp; 8 cout<<ans<<endl; 9 }