洛谷P2215 [HAOI2007]上升序列——题解

题目传送门
题目大意:
询问字典序最小的长度为L的上升子序列,不存在则输出Impossible


思考过程:
回忆 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;   
}

猜你喜欢

转载自blog.csdn.net/qq_39662197/article/details/80065788