题目描述
对于一个给定的 S=\{a_1,a_2,a_3,…,a_n\}S={a1,a2,a3,…,an} ,若有 P=\{a_{x_1},a_{x_2},a_{x_3},…,a_{x_m}\}P={ax1,ax2,ax3,…,axm} ,满足 (x_1<x_2<…<x_m)(x1<x2<…<xm) 且 (a_{x_1}<a_{x_2}<…<a_{x_m})(ax1<ax2<…<axm) 。那么就称P为S的一个上升序列。如果有多个P满足条件,那么我们想求字典序最小的那个。
任务
给出 SS 序列,给出若干询问。对于第 ii 个询问,求出长度为 L_iLi 的上升序列,如有多个,求出字典序最小的那个(即首先 x_1x1 最小,如果不唯一,再看 x_2x2 最小……),如果不存在长度为 L_iLi 的上升序列,则打印Impossible
.
输入输出格式
输入格式:
第一行一个 NN ,表示序列一共有 NN 个元素
第二行 NN 个数,为 a_1, a_2 , \cdots , a_na1,a2,⋯,an
第三行一个 MM ,表示询问次数。下面接 MM 行每行一个数 LL ,表示要询问长度为 LL 的上升序列。
输出格式:
对于每个询问,如果对应的序列存在,则输出,否则打印Impossible
.
输入输出样例
输入样例#1: 复制
6 3 4 1 2 3 6 3 6 4 5
输出样例#1: 复制
Impossible 1 2 3 6 Impossible
说明
数据范围
N \le 10000N≤10000
M \le 1000M≤1000
解题思路:题目要求得数组下标字典序最小的满足要求的序列。例如 4 5 6 7 1 2 3 4 k=4 则输出4 5 6 7
首先定义f[i]为以i开头的最长递增子序列的长度。那么从前往后贪心的求满足题意的位置,即可达到下标字典序最小。
f[i]数组数组就是倒着求一遍LIS
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define N 10005
#define sca(x) scanf("%d",&x)
int n,m;
int a[N],b[N],f[N];
int Find(int r,int k)
{
int l=1;
while(l<=r)
{
int m=(l+r)>>1;
if(b[m]>k)l=m+1;
else r=m-1;
}
return l;
}
int main()
{
sca(n);
for(int i=1;i<=n;i++)
{
sca(a[i]);
}
int r=0;
int mm=0;
for(int i=n;i>=1;i--)
{
if(a[i]<b[r])
{
b[r+1]=a[i];
f[i]=++r;
mm=max(f[i],mm);
}
else
{
int p=Find(r,a[i]);
b[p]=a[i];
f[i]=p;
r++;
mm=max(f[i],mm);
}
}
sca(m);
while(m--)
{
int k;sca(k);
if(k>mm)
{
printf("Impossible\n");
continue;
}
int last=0;
for(int i=1;i<=n;i++)
{
if(a[i]>last && f[i]>=k)
{
printf("%d",a[i]);
if(k==1)printf("\n");
else printf(" ");
k--,last=a[i];
if(k==0)break;
}
}
}
}