嘘~ 正在从服务器偷取页面 . . .

洛谷P2215 [HAOI2007]上升序列 题解


洛谷P2215 [HAOI2007]上升序列 题解

题目链接:P2215 [HAOI2007]上升序列

题意

对于一个给定的 \(S=\{a_1,a_2,a_3,…,a_n\}\) , 若有 \(P=\{a_{x_1},a_{x_2},a_{x_3},…,a_{x_m}\}\) , 满足 \((x_1<x_2<…<x_m)\)\((a_{x_1}<a_{x_2}<…<a_{x_m})\) 。那么就称 \(P\)\(S\) 的一个上升序列。如果有多个 \(P\) 满足条件,那么我们想求字典序最小的那个。

任务:

给出 \(S\) 序列,给出若干询问。对于第 \(i\) 个询问,求出长度为 \(L_i\) 的上升序列,如有多个,求出字典序最小的那个(即首先 \(x_1\) 最小,如果不唯一,再看 \(x_2\) 最小……),如果不存在长度为 \(L_i\) 的上升序列,则打印 Impossible

输入格式

第一行一个 \(N\),表示序列一共有 \(N\) 个元素。

第二行 \(N\) 个数,为 \(a_1, a_2 , \cdots , a_n\)

第三行一个 \(M\),表示询问次数。下面接 \(M\) 行每行一个数 \(L\),表示要询问长度为 \(L\) 的上升序列。

输出格式

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

数据范围

\(N \le 10000\)\(M \le 1000\),保证数据随机。

假设某个询问的答案是 \(a_i\) 开头

那下一步选 \(a_{i+1}\) 会导致什么呢?

如果 \(a_i,a_{i+1},a_{j_1},a_{j_2},\cdots.a_{j_{L-2}}\) 能构成一个长 \(L\) 的上升子序列,那没问题

但是如果 \(a_{i},a_{i+1}\) ,后面再怎么拼都拼不出长 \(L\) 的上升子序列,我们就不能选

从这个过程中,我们可以发现,当前这个数是否添加到答案的上升序列

取决于它能否在之后的决策中构成一个符合答案长度的序列

\(g_i\) 表示以 \(i\) 开头能构成多长的上升子序列

其实就是后 \(n-i+1\) 个数,能构成多长的不下降子序列

于是我们倒着跑一遍不下降子序列,得到 \(g_i\)

对于询问,直接 \(O(n)\) 跑就好啦

时间复杂度 \(O(n \log n+nm)\)

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdarg>
#include <cmath>
#include <iomanip>
#include <random>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N ((int)(1e4+15))

int n,Q,p,cnt,a[N],g[N],f[N];
int cmp(int x,int y){return a[x] > a[y];}
void solve(int len)
{
    int lst=-INF;
    for(int i=1; i<=n && len; i++)
        if(a[i] > lst && g[i] >= len)
            cout << (lst=a[i]) << " \n"[!(--len)];
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n;
    for(int i=1; i<=n; i++) cin >> a[i];
    f[cnt=1]=n; g[n]=1;
    for(int i=n-1; i; i--)
    {
        p=lower_bound(f+1,f+1+cnt,i,cmp)-f;
        f[p > cnt ? ++cnt : p]=i; g[i]=p;
    }
    for(cin >> Q; Q--; )
    {
        cin >> p;
        if(p <= cnt)solve(p);
        else cout << "Impossible\n";
    }
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录