- 题面描述
- 对于一个给定的\(S=\{a_1,a_2,a_3,…,a_n\}\),若有\(P=\{a_{x_1},a_{x_2},a_{x_3},…,a_{x_m}\}\),满足\((x_1 < x_2 < … < x_m)\)且\(( a_{x_1} < a_{x_2} < … < a_{x_m})\)。那么就称\(P\)为\(S\)的一个上升序列。如果有多个\(P\)满足条件,那么我们想求字典序最小的那个。任务给出S序列,给出若干询问。对于第\(i\)个询问,求出长度为\(L_i\)的上升序列,如有多个,求出字典序最小的那个(即首先\(x_1\)最小,如果不唯一,再看\(x_2\)最小……),如果不存在长度为\(L_i\)的上升序列,则打印
Impossible.
- 输入格式
- 第一行一个\(N\),表示序列一共有\(N\)个元素第二行\(N\)个数,为\(a_1,a_2,…,a_n\) 第三行一个\(M\),表示询问次数。下面接\(M\)行每行一个数\(L\),表示要询问长度为L的上升序列。\(N\leq 10^4,M\leq 10^3\)
- 输出格式
- 对于每个询问,如果对应的序列存在,则输出,否则打印
Impossible.
- 题解
- 不要被题面坑了,题面中的字典序不是指\(a_i\),而是指下标。
- 考虑反过来做最长下降子序列,获得每个点相后最长上升子序列长度。
- 每次询问,按字典序贪心,从前往后扫,可行就加入。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=1e4+5;
const int MAXM=1e3+5;
int n,m;
int a[MAXN],f[MAXN];
int b[MAXN],mxl;
int qry(int x){
int l=1,r=n+1,mid;
while (l+1<r){
mid=(l+r)>>1;
if (b[mid]>x) l=mid;
else r=mid;
}
return l;
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
f[n]=1; b[1]=a[n];
for (int i=n-1;i>=1;i--){
int len=qry(a[i]);
f[i]=len+1;
mxl=max(mxl,f[i]);
if (b[len+1]<a[i]) b[len+1]=a[i];
}
scanf("%d",&m);
for (int i=1;i<=m;i++){
int l; scanf("%d",&l);
if (l>mxl){
printf("Impossible\n");
continue;
}
else {
int las=0;
for (int j=1;j<=n&&l>0;j++){
if (f[j]>=l&&a[j]>las){
printf("%d ",a[j]);
l--; las=a[j];
}
}
printf("\n");
}
}
return 0;
}