JZYZOJ1261 字典序最小的lis

 

求字典序方法:

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 }
View Code

 

posted @ 2017-11-04 16:23  鲸头鹳  阅读(331)  评论(0编辑  收藏  举报