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$; 否则,由于题目要求下标字典序最小,那么贪心从前往后扫能输出就输出,即记录前一个的值,当前值大于上一个值时就输出。

代码:

 1 // luogu-judger-enable-o2
 2 #include<bits/stdc++.h>
 3 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
 4 #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
 5 #define Max(a,b) ((a)>(b)?(a):(b))
 6 #define il inline
 7 using namespace std;
 8 const int N=10005;
 9 int n,m,x,a[N],f[N],mx[N];
10 il int gi(){
11     int a=0;char x=getchar();bool f=0;
12     while((x<'0'||x>'9')&&x!='-')x=getchar();
13     if(x=='-')x=getchar(),f=1;
14     while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
15     return f?-a:a;
16 }
17 int main(){
18     n=gi();
19     For(i,1,n) a[i]=gi(),f[i]=1;
20     mx[n]=1;
21     Bor(i,1,n-1) {
22         For(j,i+1,n)
23             if(f[i]>mx[i+1]+1)break;
24             else if(a[i]<a[j]&&f[i]<f[j]+1)f[i]=f[j]+1;
25         mx[i]=Max(mx[i+1],f[i]);
26     }
27     m=gi();
28     while(m--){
29         x=gi();
30         if(x<=mx[1]){
31             int p=-520;
32             For(i,1,n){
33                 if(!x)break;
34                 if(f[i]>=x&&a[i]>p)printf("%d ",a[i]),x--,p=a[i];
35             }
36             printf("\n");
37         }
38         else printf("Impossible\n");
39     }
40     return 0;
41 }

猜你喜欢

转载自www.cnblogs.com/five20/p/9050767.html