题目传送门
题目大意:
询问字典序最小的长度为L的上升子序列,不存在则输出Impossible
思考过程:
回忆
nlogn
n
l
o
g
n
的最长上升子序列求法,dp[i]表示长度为i的上升子序列的末位最小为dp[i],这里因为对于每一个元素,我们需要知道以他为开头的最长上升子序列的长度为多少,所以我们倒过来求一遍最长下降子序列就好了。(注意题目要求的是字典序最小,不是数值最小!)
具体做法:
1.从后往前求一遍最长下降子序列(上面的dp这里用best数组储存,这里的f代表以该元素为开头的最长上升子序列的长度为多少)
2.输出答案时首先看best数组,不存在这么长的上升子序列直接输出Impossible,否则从第一个元素开始往后扫,如果当前元素的f值大于等于还需要的序列长度就将该元素输出,知道还需要的序列长度降为0
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e4+100,maxm=1e3+100;
int cnt,n,m;
int best[maxn],f[maxn],a[maxn];
int find(int x)
{
int l=1,r=cnt,nowans;
while(l<=r)
{
int mid=(l+r)>>1;
if(x<best[mid]) { nowans=mid;l=mid+1; }
else r=mid-1;
}
return nowans;
}
void put_out(int x)
{
int now=1,last=0;
while(x)
{
if(f[now]<x||a[now]<=last) { now++;continue; }
printf("%d ",a[now]);
last=a[now];
now++;x--;
}
printf("\n");
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=n;i>=1;i--)
{
int t=find(a[i]);
f[i]=t+1;cnt=max(cnt,f[i]);
best[t+1]=max(best[t+1],a[i]);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
if(x>cnt) { printf("Impossible\n");continue; }
put_out(x);
}
return 0;
}