最长上升子序列有两种递推方式。
1:f [ i ] 表示以第 i 个数结尾的最长上升子序列长度。
2:f [ i ] 表示以第 i 个数开始的最长上升子序列长度。
对于本题,要特别注意对字典序最小的规定。
我一开始以为是得到的数字序列的字典序最小,还记录了前驱和一大堆东西,然而全WA了。
后来才发现字典序最小是对应的下标序列最小。
所以对于本题,我们要用第二种方式也就是求出以每个数开始的最长上升子序列长度。
因为字典需最小,所以下标要尽量靠前。
对于每个查询,我们从头开始扫描,只要第i个数 f [ i ] >= L 且 a [ i ] > last ,我们就可以将其放入最长上升子序列中且一定满足字典序最小。 last 代表我们上一个选入的数,同时每选一个数,序列剩下长度就减一,对应 --L 。
// q.c
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
const int M=10000+10;
int n,m,maxx,d[M],f[M];
void lis() {
for(int i=n-1;i>=1;i--) {
int k=0;
for(int j=i+1;j<=n;j++)
if(d[i]<d[j]&&f[j]>k)
k=f[j];
f[i]=k+1;
maxx=max(maxx,f[i]);
}
}
void solve(int x) {
int last=0;
for(int i=1;i<=n;i++)
if(f[i]>=x&&d[i]>last) {
printf("%d ",d[i]);
last=d[i]; x--;
if(!x) break;
}
printf("\n");
}
int main() {
freopen("lis.in","r",stdin);
freopen("lis.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&d[i]),f[i]=1;
lis(); int x;
scanf("%d",&m);
for(int i=1;i<=m;i++) {
scanf("%d",&x);
if(x>maxx) printf("Impossible\n");
else solve(x);
}
return 0;
}