【bzoj1046】[HAOI2007]上升序列
首先求出以每个数为开头上升序列长度,即倒着做最长下降子序列
然后,把字典序尽量小的放前面
即若要求的序列长度为x,如果以第一个数(字典序最小的数)开头的最长上升子序列大等于x,则将它放在答案第一个,第二个数开头小于x,则舍弃,第三个大于x-1,放答案第二个,以此类推
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 using namespace std; 8 9 typedef long long LL; 10 11 #ifdef WIN32 12 #define orz "%lld" 13 #else 14 #define orz "%I64d" 15 #endif 16 17 #define MAXN 10010 18 int f[MAXN],a[MAXN],b[MAXN]; 19 int n,m; 20 int ans; 21 int x; 22 23 void work(int x) 24 { 25 int res=0; 26 for (int i=1;i<=n;i++) 27 if (f[i]>=x && a[i]>res) 28 { 29 printf("%d",a[i]); 30 if (x!=1) 31 printf(" "); 32 res=a[i]; 33 x--; 34 if (!x) 35 break; 36 } 37 printf("\n"); 38 } 39 40 int find(int x) 41 { 42 int l=1,r=ans,tmp=0; 43 while (l<=r) 44 { 45 int m=(l+r)>>1; 46 if (b[m]>x) 47 tmp=m,l=m+1; 48 else 49 r=m-1; 50 } 51 return tmp; 52 } 53 54 void get() 55 { 56 for (int i=n;i;i--) 57 { 58 int t=find(a[i]); 59 f[i]=t+1; 60 ans=max(ans,t+1); 61 //b[t+1]=min(b[t+1],a[i]); 62 if(b[t+1]<a[i]) 63 b[t+1]=a[i]; 64 } 65 } 66 67 int main() 68 { 69 scanf("%d",&n); 70 for (int i=1;i<=n;i++) 71 scanf("%d",&a[i]); 72 get(); 73 scanf("%d",&m); 74 while (m--) 75 { 76 scanf("%d",&x); 77 if (x<=ans) 78 work(x); 79 else 80 printf("Impossible\n"); 81 } 82 return 0; 83 }