• BZOJ 1046 上升序列


    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

    Source

    这题是对单调队列求最长上升序列的应用。

    由于要求字典序最小的,我们得反过来求最长最长下降子序列(从末尾dp起)。g[i]表示从末尾起长度为i的最长下降子序列的第i为的最大值,f[i]表示从i开头的最长上升子序列的长度,len表示当前从末尾开始最长下降序列的长度。很明显,对于序列中的每一位s[i],我们可以在g中二分出最大的一个i使得大于g[i]>s[i](g具有单调性),之后f[i]=i+1,g[i+1]=s[i],len=max(len,i+1)。

    最后输出长度为a序列时,我们可以从前往后扫。

    1 int cur = -(1<<30);
    2 for (int i = 1;a;++ i)
    3     if (f[i] >= a && s[i] > cur)
    4     {
    5         --a; cur = s[i]; printf("%d",s[i]);
    6         if (a) putchar(' ');
    7     }
    View Code
     1 #include<iostream>
     2 #include<cstdlib>
     3 #include<cstdio>
     4 using namespace std;
     5 
     6 #define maxn 10010
     7 int f[maxn],g[maxn],s[maxn],n,len;
     8 
     9 inline int find(int k)
    10 {
    11     int l = 1,r = len,mid;
    12     while (l <= r)
    13     {
    14         mid = (l + r) >> 1;
    15         if (k >= g[mid]) r = mid - 1;
    16         else l = mid + 1;
    17     }
    18     return l;
    19 }
    20 
    21 inline void ready()
    22 {
    23     for (int i = n;i;--i)
    24     {
    25         int pos = find(s[i]);
    26         f[i] = pos; len = max(pos,len); g[pos] = s[i];
    27     }
    28 }
    29 
    30 int main()
    31 {
    32     scanf("%d",&n);
    33     for (int i = 1;i <= n;++i) scanf("%d",s+i);
    34     ready();
    35     int T,a; scanf("%d",&T);
    36     while (T--)
    37     {
    38         scanf("%d",&a);
    39         if (a > len) puts("Impossible");
    40         else
    41         {
    42             int cur = -(1<<30);
    43             for (int i = 1;a;++ i)
    44                 if (f[i] >= a && s[i] > cur)
    45                 {
    46                     --a; cur = s[i]; printf("%d",s[i]);
    47                     if (a) putchar(' ');
    48                 }
    49             putchar('
    ');
    50          }
    51     }
    52 }
    View Code
  • 相关阅读:
    vue基础八(路由组件)
    vue基础(七),同源策略以及跨域,vuex
    如何将注释的代码折叠
    axios发请求的基本语法:
    vue基础(六)全局事件总线
    vue基础(五),对todos的操作
    Android仿IOS的AssistiveTouch的控件EasyTouch实现
    CentOS下配置HTTPS访问主机并绑定访问端口号
    Effective Java:对于所有对象都通用的方法
    物联网操作系统HelloX开发者入门指南
  • 原文地址:https://www.cnblogs.com/mmlz/p/4293921.html
Copyright © 2020-2023  润新知