zoukankan      html  css  js  c++  java
  • BZOJ1046 [HAOI2007]上升序列

    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+贪心

    解题报告:

      其实挺水的却花了我半个多小时。

      显然先DP做最长上升子序列,然后做贪心。显然从前往后扫,每次扫到第一个发现长度大于要求长度,且当前值>last的就输出,然后长度--,last=当前值。这样贪心应该是正确的。

      我WA了两发,因为当长度变成0时应该及时跳出,而不是往后做。

      然后我还学了一下nlogn的最长上升子序列的DP,思想也很简单,就是从后往前做,然后维护每种长度当前的开始的结点的值最大值,对于每个i都二分查找出它之后可以接的最大长度。这显然是nlogn的。

     

      n^2 的做法:

     1 //It is made by jump~
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <algorithm>
     8 #include <ctime>
     9 #include <vector>
    10 #include <queue>
    11 #include <map>
    12 #include <set>
    13 #ifdef WIN32   
    14 #define OT "%I64d"
    15 #else
    16 #define OT "%lld"
    17 #endif
    18 using namespace std;
    19 typedef long long LL;
    20 const int MAXN = 10011;
    21 const int inf = (1<<30);
    22 int n,m,maxl;
    23 int a[MAXN],f[MAXN];
    24 
    25 inline int getint()
    26 {
    27        int w=0,q=0;
    28        char c=getchar();
    29        while((c<'0' || c>'9') && c!='-') c=getchar();
    30        if (c=='-')  q=1, c=getchar();
    31        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
    32        return q ? -w : w;
    33 }
    34 
    35 inline void work(){
    36     n=getint(); for(int i=1;i<=n;i++) a[i]=getint(),f[i]=1;
    37     int len;
    38     for(int i=n-1;i>=1;i--) {//事实上可以nlogn做最长上升子序列,记录每种长度的出现的最大的值,然后二分查找找到能够匹配的最大长度值
    39     len=0; 
    40     for(int j=i+1;j<=n;j++) {
    41         if(a[j]>a[i] && f[j]>=len) len=f[j];
    42     } 
    43     f[i]=len+1; maxl=max(f[i],maxl);
    44     }
    45     m=getint(); int x,last;
    46     for(int o=1;o<=m;o++) {//实际上这里不能直接输出,应该不断往后找可行解
    47     if(o>1) printf("
    ");
    48     x=getint(); last=-inf;
    49     if(maxl<x) { printf("Impossible"); continue; }
    50     for(int i=1;i<=n;i++) {
    51         if(f[i]>=x && a[i]>last) {
    52         if(last!=-inf) printf(" ");
    53         last=a[i]; x--;
    54         printf("%d",a[i]);
    55         if(!x) break;//及时跳出
    56         }
    57     }
    58     }
    59 }
    60 
    61 int main()
    62 {
    63   work();
    64   return 0;
    65 }

      nlogn的做法:

      

     1 //It is made by jump~
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <algorithm>
     8 #include <ctime>
     9 #include <vector>
    10 #include <queue>
    11 #include <map>
    12 #include <set>
    13 #ifdef WIN32   
    14 #define OT "%I64d"
    15 #else
    16 #define OT "%lld"
    17 #endif
    18 using namespace std;
    19 typedef long long LL;
    20 const int MAXN = 10011;
    21 const int inf = (1<<30);
    22 int n,m;
    23 int a[MAXN],f[MAXN],c[MAXN];//c[i]表示长度为i的开始结点的值的最大值
    24 int maxl;
    25 
    26 inline int getint()
    27 {
    28        int w=0,q=0;
    29        char c=getchar();
    30        while((c<'0' || c>'9') && c!='-') c=getchar();
    31        if (c=='-')  q=1, c=getchar();
    32        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
    33        return q ? -w : w;
    34 }
    35 
    36 inline int search(int x){//二分查找
    37     int l=0,r=maxl,mid; int pos;
    38     while(l<=r) {
    39     mid=(l+r)>>1;
    40     if(c[mid]>x) pos=mid,l=mid+1;
    41     else r=mid-1;
    42     }
    43     return pos;
    44 }
    45 
    46 inline void work(){
    47     n=getint(); for(int i=1;i<=n;i++) a[i]=getint();
    48     int now; c[0]=inf;
    49     for(int i=n;i>=1;i--) {//倒着查找
    50     now=search(a[i]); f[i]=now+1;
    51     c[f[i]]=max(c[f[i]],a[i]);
    52     maxl=max(maxl,f[i]);
    53     }
    54     m=getint(); int last;
    55     for(int o=1;o<=m;o++) {
    56     if(o!=1) printf("
    ");    
    57     now=getint(); last=-inf;
    58     if(now>maxl) { printf("Impossible"); continue; }
    59     for(int i=1;i<=n;i++){
    60         if(f[i]>=now && a[i]>last) {
    61         printf("%d",a[i]);
    62         if(now!=1) printf(" "); else break;//记得及时退出
    63         now--; last=a[i];        
    64         }
    65     }
    66     }
    67 }
    68 
    69 int main()
    70 {
    71   work();
    72   return 0;
    73 }
  • 相关阅读:
    全站防止SQL注入类
    asp.net 技术网站
    Tekla API 常见问题摘录整理
    C#退出程序结束线程
    C#MetroModernUI库应用实例 WinForm窗体UI的美化
    获取项目物理根目录绝对路径
    计算两个时间月数的差
    centos7安装wps软件
    10 安全运维管理 10.11备份与恢复管理
    10 安全运维管理 10.14外包运维管理
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5708925.html
Copyright © 2011-2022 走看看