标签:
首先求出以每个数为开头上升序列长度,即倒着做最长下降子序列
然后,把字典序尽量小的放前面
即若要求的序列长度为x,如果以第一个数(字典序最小的数)开头的最长上升子序列大等于x,则将它放在答案第一个,第二个数开头小于x,则舍弃,第三个大于x-1,放答案第二个,以此类推
#include<algorithm>#include<iostream>#include<cstdlib>#include<cstring>#include<cstdio>#include<cmath>using namespace std;typedef long long LL;#ifdef WIN32#define orz "%lld"#else#define orz "%I64d"#endif#define MAXN 10010int f[MAXN],a[MAXN],b[MAXN];int n,m;int ans;int x;void work(int x){ int res=0; for (int i=1;i<=n;i++) if (f[i]>=x && a[i]>res) { printf("%d",a[i]); if (x!=1) printf(" "); res=a[i]; x--; if (!x) break; } printf("\n");}int find(int x){ int l=1,r=ans,tmp=0; while (l<=r) { int m=(l+r)>>1; if (b[m]>x) tmp=m,l=m+1; else r=m-1; } return tmp;}void get(){ for (int i=n;i;i--) { int t=find(a[i]); f[i]=t+1; ans=max(ans,t+1); //b[t+1]=min(b[t+1],a[i]); if(b[t+1]<a[i]) b[t+1]=a[i]; }}int main(){ scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]); get(); scanf("%d",&m); while (m--) { scanf("%d",&x); if (x<=ans) work(x); else printf("Impossible\n"); } return 0;}标签:
原文地址:http://www.cnblogs.com/yangjiyuan/p/5343113.html