P2215 [HAOI2007]上升序列
Posted five20
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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.
输入输出样例
6
3 4 1 2 3 6
3
6
4
5
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 }
以上是关于P2215 [HAOI2007]上升序列的主要内容,如果未能解决你的问题,请参考以下文章