Evanyou Blog 彩带

P2215 [HAOI2007]上升序列

题目描述

对于一个给定的S={a1,a2,a3,…,an},若有P={ax1,ax2,ax3,…,axm},满足(x1<x2<…<xm) 且(ax1<ax2<…<axm)。那么就称P为S的一个上升序列。如果有多个P满足条件,那么我们想求字典序最小的那个。

任务 给出S序列,给出若干询问。对于第i个询问,求出长度为Li的上升序列,如有多个,求出字典序最小的那个(即首先x1最小,如果不唯一,再看x2最小……),如果不存在长度为Li的上升序列,则打印Impossible.

输入输出格式

输入格式:

第一行一个N,表示序列一共有N个元素

第二行N个数,为a1,a2,…,an

第三行一个M,表示询问次数。下面接M行每行一个数L,表示要询问长度为L的上升序列。

输出格式:

对于每个询问,如果对应的序列存在,则输出,否则打印Impossible.

输入输出样例

输入样例#1: 
6
3 4 1 2 3 6
3
6
4
5
输出样例#1: 
Impossible
1 2 3 6
Impossible

说明

数据范围

N<=10000

M<=1000

 

Solution:

  本题简直有毒!数据包也有毒!~调了我好久啊!~

  其实本题一个很简单的思路就是:

  先暴力$O(n^2)$处理出以每一位为起点最长上升子序列的长度,那么直接该成倒序即可,这样$f[i]$就表示以$i$为起点最长上升子序列长度。

  然后每次询问长度为$x$的上升子序列是否存在:当$x > L_{max}$时,则直接输出$Impossible$; 否则,由于题目要求下标字典序最小,那么贪心从前往后扫能输出就输出,即记录前一个的值,当前值大于上一个值时就输出。

代码:

 

#include<bits/stdc++.h>
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
#define Max(a,b) ((a)>(b)?(a):(b))
#define il inline
using namespace std;
const int N=10005;
int n,m,x,a[N],f[N],mx[N];
il int gi(){
    int a=0;char x=getchar();bool f=0;
    while((x<'0'||x>'9')&&x!='-')x=getchar();
    if(x=='-')x=getchar(),f=1;
    while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
    return f?-a:a;
}
int main(){
    n=gi();
    For(i,1,n) a[i]=gi(),f[i]=1;
    mx[n]=1;
    Bor(i,1,n-1) {
        For(j,i+1,n)
            if(f[i]>mx[i+1]+1)break;
            else if(a[i]<a[j]&&f[i]<f[j]+1)f[i]=f[j]+1;
        mx[i]=Max(mx[i+1],f[i]);
    }
    m=gi();
    while(m--){
        x=gi();
        if(x<=mx[1]){
            int p=-520;
            For(i,1,n){
                if(!x)break;
                if(f[i]>=x&&a[i]>p)printf("%d ",a[i]),x--,p=a[i];
            }
            printf("\n");
        }
        else printf("Impossible\n");
    }
    return 0;
}

 

 

 

 

posted @ 2018-05-17 14:04  five20  阅读(158)  评论(0编辑  收藏  举报
Live2D