[HAOI2007] 上升序列

Posted qjs12

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HAOI2007] 上升序列相关的知识,希望对你有一定的参考价值。

  最长上升子序列有两种递推方式。

  1:f [ i ] 表示以第 i 个数结尾的最长上升子序列长度。

  2:f [ i ] 表示以第 i 个数开始的最长上升子序列长度。

  对于本题,要特别注意对字典序最小的规定。

  我一开始以为是得到的数字序列的字典序最小,还记录了前驱和一大堆东西,然而全WA了。

  后来才发现字典序最小是对应的下标序列最小。

  所以对于本题,我们要用第二种方式也就是求出以每个数开始的最长上升子序列长度。

  因为字典需最小,所以下标要尽量靠前。

  对于每个查询,我们从头开始扫描,只要第i个数 f [ i ] >= L 且 a [ i ] > last ,我们就可以将其放入最长上升子序列中且一定满足字典序最小。 last 代表我们上一个选入的数,同时每选一个数,序列剩下长度就减一,对应 --L 。

 

// q.c

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
const int M=10000+10;
int n,m,maxx,d[M],f[M];
void lis() {
	for(int i=n-1;i>=1;i--) {
		int k=0;
		for(int j=i+1;j<=n;j++) 
			if(d[i]<d[j]&&f[j]>k) 
				k=f[j];
		f[i]=k+1;
		maxx=max(maxx,f[i]);
	}
}
void solve(int x) {
	int last=0;
	for(int i=1;i<=n;i++) 
		if(f[i]>=x&&d[i]>last) {
			printf("%d ",d[i]);
			last=d[i]; x--;
			if(!x) break;
		}
	printf("\n");
}
int main() {
	freopen("lis.in","r",stdin);
	freopen("lis.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&d[i]),f[i]=1;
	lis(); int x;
	scanf("%d",&m);
	for(int i=1;i<=m;i++) {
		scanf("%d",&x);
		if(x>maxx) printf("Impossible\n");
		else solve(x);
	}
	return 0;
}

 

以上是关于[HAOI2007] 上升序列的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1046[HAOI2007]上升序列

1046: [HAOI2007]上升序列(dp)

luogu P2215 [HAOI2007]上升序列

bzoj1046[HAOI2007]上升序列

Bzoj1046: [HAOI2007]上升序列

BZOJ 1046 1046: [HAOI2007]上升序列