P2215 [HAOI2007]上升序列 (最长上升子序列)

题目描述

对于一个给定的 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;
            }
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值