现在的位置: 首页 > 综合 > 正文

BZOJ 1046: [HAOI2007]上升序列

2018年01月13日 ⁄ 综合 ⁄ 共 1334字 ⁄ 字号 评论关闭

Description

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

Input

第一行一个N,表示序列一共有N个元素第二行N个数,为a1,a2,…,an 第三行一个M,表示询问次数。下面接M行每行一个数L,表示要询问长度为L的上升序列。

Output

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

Sample Input

6

3 4 1 2 3 6

3

6

4

5

Sample Output

Impossible

1 2 3 6

Impossible

HINT

数据范围

N<=10000

M<=1000

题解

为了保证所谓字典序“最小”。可以倒着做一边最长下降子序列。然后对于每个问题枚举统计答案即可。有时候想太多反而会错。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define inf 1<<30
using namespace std;
int n,m,a[10005];
int f[10005],stk[10005],top,maxf;
void init()
{
	scanf("%d",&n);
	int i;
	for(i=1;i<=n;i++) scanf("%d",&a[i]);
}
int erf(int x)
{
	int l=0,r=top,mid,w;
	while(l<=r)
	   {mid=(l+r)>>1;
	    if(stk[mid]<=x) r=mid-1;
	    else {w=mid; l=mid+1;}
	   }
	return w;
}
void predp()
{
	int i,w;
	f[n]=1; stk[0]=inf;
	stk[1]=a[n]; top=1;
	for(i=n-1;i>0;i--)
	   {w=erf(a[i]);
	    f[i]=w+1; 
	    if(w==top) {top++; stk[top]=a[i];}
		else stk[w+1]=max(stk[w+1],a[i]);
	   }
	for(i=1;i<=n;i++) maxf=max(maxf,f[i]);
}
void work()
{
	scanf("%d",&m);
	int i,j,x,now;
	for(i=1;i<=m;i++)
	   {scanf("%d",&x);
	    if(x>maxf) puts("Impossible");
	    else
	       {now=-inf;
			for(j=1;j<=n;j++)
		       {if(f[j]>=x&&a[j]>now)
				   {if(x==1) {printf("%d\n",a[j]); break;}
				    else
				       {x--; printf("%d ",a[j]); now=a[j];}
				   }
			   }
		   }
	   }
}
int main()
{
	init(); predp();
	work();
	return 0;
}

抱歉!评论已关闭.