分析:
给一个序列,求出每个位置结尾的最长上升子序列
O(n^2) 超时
#include "cstdio" #include "algorithm" #define N 1005 #define INF 0X3f3f3f3f using namespace std; int a[N]; int dp[N]; void solve(int n) { for(int i=0;i<n;i++) { dp[i]=1; for(int j=0;j<i;j++)///往前找寻美妙的回忆 { if(a[j]<a[i]) { dp[i]=std::max(dp[i],dp[j]+1); } } } for(int i=0;i<n;i++) { if(i==0) printf("%d",dp[0]); else printf(" %d",dp[i]); } printf(" "); } int main() { int t,n; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&a[i]); solve(n); } }
优化为O(nlogn) AC
#include "cstdio" #define N 100005 #include "algorithm" using namespace std; int n; int a[N]; int dp[N]; int ans[N]; int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&a[0]); int top=1;///最长上升子序列长度 dp[1]=a[0];///=最后一个元素 ans[0]=top;///每个位置的 最长上升..长度 for(int j=1;j<n;j++)///对每个元素 { scanf("%d",&a[j]); if(a[j]>dp[top])///变长 { top++; dp[top]=a[j]; ans[j]=top; } else { int pos=lower_bound(dp,dp+top,a[j])-dp;///二分查找位置 替换元素 dp[pos]=a[j]; ans[j]=pos; } } for(int i=0;i<n;i++) { if(i==0) printf("%d",ans[i]); else printf(" %d",ans[i]); } printf(" "); } }
若只要最长...,只输出ans[n-1]
可将上述解法当做一模板
#include <iostream> #include <stdio.h> #include <algorithm> #include <string.h> using namespace std; int dp[20]; const int inf=0x7fffffff; int a[7]={2,1,3,4,8,5,9}; const int maxn=500005; int main() { fill(dp,dp+7,inf); for(int i=0;i<7;i++) { *lower_bound(dp,dp+7,a[i])=a[i]; } int len=lower_bound(dp,dp+7,inf)-dp; for(int i=0;i<len;i++) cout<<dp[i]<<endl; return 0; }