• bzoj 1046[HAOI2007]上升序列


    1046: [HAOI2007]上升序列

    Time Limit: 10 Sec  Memory Limit: 162 MB

    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
     
    注意 :
    这题的字典序最小指的是对应的位置最小
     
    可以倒着dp求最长下降序列, 求出到每个点的最大长度。
    这样对于一个长度为L的序列,我们从头往后扫,如果当前位置满足条件,他就可以加入到序列当中
    满足的条件是 :
    f[i] >= 剩余长度 && a[i] < a[last]
     
     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <algorithm>
     5 #define LL long long
     6 
     7 using namespace std;
     8 
     9 const int MAXN = 1e5 + 10;
    10 int N, M;
    11 LL a[MAXN];
    12 LL b[MAXN]; 
    13 LL f[MAXN];
    14 inline LL read()
    15 {
    16     LL x = 0, w = 1; char ch = 0;
    17     while(ch < '0' || ch > '9') {
    18         if(ch == '-') {
    19             w = -1;
    20         }
    21         ch = getchar();
    22     }
    23     while(ch >= '0' && ch <= '9') {
    24         x = x * 10 + ch - '0';
    25         ch = getchar();
    26     }
    27     return x * w;
    28 }
    29 
    30 int main()
    31 {
    32     N = read();
    33     for(int i = 1; i <= N; i++) {
    34         a[i] = read() * -1;    
    35     }
    36     LL cnt = 0;
    37     for(int i = N; i >= 1; i--) {
    38         int k = lower_bound(b + 1, b + cnt + 1, a[i]) - b;
    39         f[i] = k; 
    40         if(k > cnt) {
    41             cnt++;
    42         }
    43         b[k] = a[i];
    44         a[i] = a[i] * -1;
    45     }
    46     /*f[N] = 1;
    47     cout<<f[N]<<endl;
    48     for(int i = N - 1; i >= 1; i--) {
    49         for(int j = i + 1; j <= N; j++) {
    50             if(a[j] > a[i]) {
    51                 f[i] = max(f[i], f[j] + 1);
    52             }
    53         }
    54         cnt = max(cnt, f[i]);
    55         cout<<f[i]<<endl;
    56     }
    57     return 0;*/
    58     M = read();
    59     for(int i = 1; i <= M; i++) {
    60         int len = read();
    61         LL last = -1e9;
    62         if(len > cnt) {
    63             printf("Impossible");
    64         } else {
    65             for(int j = 1; j <= N; j++) {
    66                 if(f[j] >= len && a[j] > last) {
    67                     len--;
    68                     last = a[j];
    69                     printf("%lld", a[j]);
    70                     if(len > 0) {
    71                         printf(" ");
    72                     }
    73                     if(len == 0) {
    74                         break;
    75                     }
    76                 }
    77             }
    78         }
    79         printf("
    ");
    80     }
    81     return 0;
    82 }
    83 
    84 /*
    85 
    86 6
    87 3 4 1 2 3 6
    88 3
    89 6
    90 4
    91 3
    92 
    93 
    94 */
    View Code
  • 相关阅读:
    过滤非GBK字符
    打印整数数字
    std::string 方法列表
    设计模式——单例模式(Singleton )
    编程之美二进制一的个数
    Jsoncpp试用指南
    GCC下宏扩展后的++i
    关于字节对齐的sizeof的讨论
    Notepad++ 更改和定制主题
    求子数组的最大和
  • 原文地址:https://www.cnblogs.com/wuenze/p/8570406.html
Copyright © 2020-2023  润新知