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 }
  • 相关阅读:
    CodeForces 785D Anton and School
    CodeForces 785C Anton and Fairy Tale
    CodeForces 785B Anton and Classes
    CodeForces 785A Anton and Polyhedrons
    爱奇艺全国高校算法大赛初赛C
    爱奇艺全国高校算法大赛初赛B
    爱奇艺全国高校算法大赛初赛A
    EOJ 3265 七巧板
    EOJ 3256 拼音魔法
    EOJ 3262 黑心啤酒厂
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5708925.html
Copyright © 2011-2022 走看看