求字典序方法:
f[i]表示i位数字的最长上升子序列长度,len为最长上升子序列长度,ans[t]为第t位答案,maxn为ans[t+1](初始化为最大值)
倒序查找f[i]==t&&a[i]<maxn的a[i],每找到一个则存入答案,t--;
g[i]表示排名i的最小的数
原理:显然a[i]前不可能有一个a[j]<a[i]&&f[j]>=f[i]的a[j],所以倒序可行
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const int bn=50010; 8 int n,len; 9 long long a[bn]={},f[bn]={},g[bn]={},ans[bn]={}; 10 inline int search(int x){ 11 int left=0,right=len,mid; 12 while(left+1<right){ 13 mid=(left+right)/2; 14 if(a[g[mid]]<x){ 15 left=mid; 16 } 17 else{ 18 right=mid; 19 } 20 } 21 if(a[g[right]]<x){ 22 left=right; 23 } 24 return left; 25 } 26 int main(){ 27 //freopen("wtf.in","r",stdin); 28 int i=1; 29 while(cin>>a[i]){ 30 i++; 31 } 32 n=i-1; 33 a[0]=-9999999999LL; 34 f[1]=1; 35 g[1]=1; 36 len=1; 37 for(int i=2;i<=n;i++){ 38 if(a[i]>a[g[len]]){ 39 len++; 40 g[len]=i; 41 f[i]=len; 42 } 43 else{ 44 int t=search(a[i]); 45 f[i]=t+1; 46 if(a[g[t+1]]>a[i]){ 47 g[t+1]=i; 48 } 49 } 50 } 51 int t=len; 52 long long maxn=9999999999LL; 53 for(int i=n;i>=1;i--){ 54 if(!t){ 55 break; 56 } 57 if(f[i]==t&&a[i]<maxn){ 58 maxn=a[i]; 59 ans[t]=a[i]; 60 t--; 61 } 62 } 63 for(int i=1;i<=len;i++){ 64 printf("%d ",ans[i]); 65 } 66 cout<<endl; 67 return 0; 68 }