P2215 [HAOI2007] 上升序列题解

题目大意

对于一个集合 $ S $,对于 $ S $ 中长度为 $ m $ 的子序列 $ P $,在集合 $ P $ 中如果 $ P_1<P_2<...<P_m $ 那么我们称 $ P $ 为 $ S $ 的一个上升序列。如果有多个 $ P $ 满足条件我们就输出最小的那个,如果没有完成条件的 $ P $ 则输出 Impossible

思路

对于一个含有 $ n $ 个元素的集合,我们求出这个集合每一个最长上升序列总时间复杂度需要 $ \Omicron(n^2) $ 看一眼数据 $ 10^4 $ 完全可以,接着对于每一个输入的 $ len $,我们直接从第一个开始暴力判断,在每次判断时维护一下当前的数,每一次最坏的时间复杂度为 $ \Omicron(n) $ 所以总时间复杂度为 $ \Omicron(m \times n ) $,由此可以算出我们完成这道题最坏的时间复杂度为 $ \Omicron(n^2 + m \times n) $ 及 $ \Omicron(1.1 \times 10^8) $ 而一秒大约能运行 $ 3 \times 10^8 $ 次,所以这道题暴力完全能过。

Code:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <queue>
#define sc(ppt) scanf("%d" , &ppt)
#define ll long long
#define prt printf
using namespace std;

const int maxn = 1e4 +  1;
int n , m , f[maxn] , a[maxn] ; 

signed main(){
	sc(n) ;
	for(int i=1 ; i<=n ; i++) sc(a[i]) ;
	for(int i=1 ; i<=n ; i++) f[i] = 1;
	for(int i=n ; i>=1 ; i--){
		for(int j=n ; j>=1 ; j--){
			if(a[j] > a[i]) f[i] = max(f[i] , f[j] + 1); // 暴力求最长子序列 
		}
	}
	sc(m) ;
	while(m --){
		int len , cnt = 0 , j = 0 , ans[maxn]; sc(len) ;
		for(int i=0 ; i<=n&&len ; i=j , len--){ // 维护序列长度 
			for(j=i+1 ; j<=n ; j++){
				if(f[j] >= len && a[j] > a[i]) break; // 用当前最长上升的子序列来判断 
			}
			if(j <= n) ans[++ cnt] = a[j]; // 维护当前这个数的状态 
			else break;
		}
		if(len != 0) prt("Impossible\n"); // 如果还需要的数的个数不为0那么说明上升子序列长度不够 
		else{
			for(int i=1 ; i<=cnt ; i++) prt("%d " , ans[i]);
			prt("\n");
		}
	}
	return 0;
}
posted @ 2024-05-30 21:22  CaoSheng  阅读(19)  评论(0)    收藏  举报