[HAOI 2007]上升序列

Description

  对于一个给定的S={a1,a2,a3,…,an},若有P={ax1,ax2,ax3,…,axm},满足(x1 < x2 < … < xm)且( ax1 < ax
2 < … < axm)。那么就称P为S的一个上升序列。如果有多个P满足条件,那么我们想求字典序最小的那个。任务给
出S序列,给出若干询问。对于第i个询问,求出长度为Li的上升序列,如有多个,求出字典序最小的那个(即首先
x1最小,如果不唯一,再看x2最小……),如果不存在长度为Li的上升序列,则打印Impossible.

Input

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

Output

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

Sample Input

6
3 4 1 2 3 6
3
6
4
5

Sample Output

Impossible
1 2 3 6
Impossible

题解

比较暴力...

首先做一般的 $lis$ 都可以获得一个数组,如 $f_i$ 表示 $i$ 这个位置以前以 $a_i$ 结尾的最长上升子序列的长度。

我们考虑反着做,记 $f_i$ 表示 $i$ 这个位置之后以 $a_i$ 开头的最长上升子序列的长度。

然后处理询问 $len$ 的时候只需要从 $1$ 到 $n$ 扫一遍,记 $last$ 为上一个选出的数, $x$ 为待选序列长度。如果 $a_i > last$ 且 $f_i geq x$ ,便选上,将 $x-1$ 。

 1 //It is made by Awson on 2018.1.4
 2 #include <set>
 3 #include <map>
 4 #include <cmath>
 5 #include <ctime>
 6 #include <queue>
 7 #include <stack>
 8 #include <cstdio>
 9 #include <string>
10 #include <vector>
11 #include <cstdlib>
12 #include <cstring>
13 #include <iostream>
14 #include <algorithm>
15 #define LL long long
16 #define LD long double
17 #define Max(a, b) ((a) > (b) ? (a) : (b))
18 #define Min(a, b) ((a) < (b) ? (a) : (b))
19 using namespace std;
20 const int N = 10000;
21 const int INF = ~0u>>1;
22 
23 int n, m, a[N+5], f[N+5], w[N+5], x, maxlen;
24 
25 void print(int x) {
26     int last = 0;
27     for (int i = 1; i <= n; i++) {
28     if (f[i] >= x && last < a[i] && x) {
29         if (last != 0) printf(" ");
30         last = a[i];
31         printf("%d", a[i]);
32         x--;
33     }
34     }
35     printf("
");
36 }
37 int dev(int l, int r, int val) {
38     int ans = 0;
39     while (l <= r) {
40     int mid = (l+r)>>1;
41     if (w[mid] > val) l = mid+1, ans = mid;
42     else r = mid-1;
43     }
44     return ans;
45 }
46 void work() {
47     scanf("%d", &n); w[0] = INF;
48     for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
49     for (int i = n; i >= 1; i--) {
50     int pos = dev(0, maxlen, a[i]); maxlen = Max(maxlen, pos+1);
51     f[i] = pos+1;
52     if (f[i] == maxlen) w[maxlen] = a[i];
53     else w[f[i]] = Max(w[f[i]], a[i]);
54     }
55     scanf("%d", &m);
56     while (m--) {
57     scanf("%d", &x);
58     if (x > maxlen) printf("Impossible
");
59     else print(x);
60     }
61 }
62 int main() {
63     work();
64     return 0;
65 }
原文地址:https://www.cnblogs.com/NaVi-Awson/p/8191760.html