• 【BZOJ】【1046】【HAOI2007】上升序列


    DP+贪心


      啊……其实是个水题,想的复杂了

      令f[i]表示以 i 为起始位置的最长上升子序列的长度,那么对于一个询问x,我们可以贪心地从前往后扫,如果f[i]>=x && a[i]>last,则x--,last=a[i]

      保证$x_i$(下标)字典序最小……

     1 /**************************************************************
     2     Problem: 1046
     3     User: Tunix
     4     Language: C++
     5     Result: Accepted
     6     Time:2116 ms
     7     Memory:1428 kb
     8 ****************************************************************/
     9  
    10 //BZOJ 1046
    11 #include<vector>
    12 #include<cstdio>
    13 #include<cstring>
    14 #include<cstdlib>
    15 #include<iostream>
    16 #include<algorithm>
    17 #define rep(i,n) for(int i=0;i<n;++i)
    18 #define F(i,j,n) for(int i=j;i<=n;++i)
    19 #define D(i,j,n) for(int i=j;i>=n;--i)
    20 #define pb push_back
    21 using namespace std;
    22 inline int getint(){
    23     int v=0,sign=1; char ch=getchar();
    24     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
    25     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
    26     return v*sign;
    27 }
    28 const int N=1e4+10,INF=~0u>>2;
    29 typedef long long LL;
    30 /******************tamplate*********************/
    31 int n,m,a[N],b[N],len,f[N],ans[N];
    32 int Find(int x){
    33     int l=1,r=len,mid,ans=len+1;
    34     while(l<=r){
    35         mid=l+r>>1;
    36         if (b[mid]<=x) ans=mid,r=mid-1;
    37         else l=mid+1;
    38     }
    39     return ans;
    40 }
    41 int main(){
    42 #ifndef ONLINE_JUDGE
    43     freopen("1046.in","r",stdin);
    44     freopen("1046.out","w",stdout);
    45 #endif
    46     n=getint();
    47     F(i,1,n) a[i]=getint();
    48     D(i,n,1){
    49         int x=Find(a[i]);
    50         f[i]=x; b[x]=a[i];
    51         if (x>len) len=x;
    52     }
    53     m=getint();int x;
    54     while(m--){
    55         x=getint();
    56         if (len<x) {puts("Impossible");continue;}
    57         int last=0;
    58         F(i,1,n)
    59             if (f[i]>=x && a[i]>last){
    60                 printf("%d",a[i]);
    61                 if (x!=1) printf(" ");
    62                 last=a[i];
    63                 x--;
    64                 if (x==0) break;
    65             }
    66         puts("");
    67     }
    68     return 0;
    69 }
    70 
    View Code

    P.S.一开始想成数值字典序最小了……如果是数值字典序的话也可做,方法类似?(以下内容与本题解法无关)

      预处理出来一张表,在这张表 f 中,f[i]里存的是最长上升子序列长度>=i 的数的下标,且满足这些数(即下标对应的数)是单调递减的。

      感觉说起来好怪……贴下代码吧

      就是满足下标单调增,但值单调减

     1 #include<vector>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<iostream>
     6 #include<algorithm>
     7 #define rep(i,n) for(int i=0;i<n;++i)
     8 #define F(i,j,n) for(int i=j;i<=n;++i)
     9 #define D(i,j,n) for(int i=j;i>=n;--i)
    10 #define pb push_back
    11 using namespace std;
    12 inline int getint(){
    13     int v=0,sign=1; char ch=getchar();
    14     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
    15     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
    16     return v*sign;
    17 }
    18 const int N=1e4+10,INF=~0u>>2;
    19 typedef long long LL;
    20 /******************tamplate*********************/
    21 int n,a[N],best,ans[N];
    22 vector<int>f[N];
    23 vector<int>::iterator tmp;
    24 int main(){
    25 #ifndef ONLINE_JUDGE
    26     freopen("1046.in","r",stdin);
    27     freopen("1046.out","w",stdout);
    28 #endif
    29     n=getint();
    30     F(i,1,n) a[i]=getint();
    31     f[1].pb(1); best=1;
    32     F(i,2,n){
    33         D(j,best,2){
    34             if (a[i]<a[f[j][f[j].size()-1]] && 
    35                 a[f[j-1][f[j-1].size()-1]]<a[i])
    36                 f[j].pb(i);
    37         }
    38         if (a[i]>a[f[best][f[best].size()-1]]){
    39             best++;
    40             f[best].pb(i);
    41         }
    42         if (a[i]<a[f[1][f[1].size()-1]]) f[1].pb(i);
    43     }
    44     int m=getint(), x;
    45     while(m--){
    46         x=getint();
    47         if (f[x].empty()){puts("Impossible");continue;}
    48         ans[x]=f[x][f[x].size()-1];
    49         D(i,x-1,1){
    50             tmp=lower_bound(f[i].begin(),f[i].end(),ans[x]);
    51             tmp--;
    52             ans[i]=*tmp;
    53         }
    54         F(i,1,x) printf("%d ",a[ans[i]]);
    55         puts("");
    56     }
    57     return 0;
    58 }
    View Code

      也是贪心地去找最优解>_>

    1046: [HAOI2007]上升序列

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 2866  Solved: 960
    [Submit][Status][Discuss]

    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

    [Submit][Status][Discuss]
  • 相关阅读:
    WindowXP 下Android 开发环境搭建
    机房收费系统个人版——DataGridView控件怎么用?
    IOS开发(64)之GCD任务最多只执行一次
    第八学 linux内核——内存寻址——段机制(2)
    Git clone远程仓库
    vi中如何跳转到指定行数
    _STORAGE_WRITE_ERROR_:./Application/Runtime/Cache/Home/f8995a0e1afcdadc637612fae5a3b585.php
    git 报错:没有权限 remote: error: unable to unlink old 'README.md' (Permission denied)
    mytop安装,使用mytop监控MySQL性能 (总结)
    一起谈.NET技术,如何解决“呈现控件时出错”的问题 狼人:
  • 原文地址:https://www.cnblogs.com/Tunix/p/4430518.html
Copyright © 2020-2023  润新知