[bzoj1046][HAOI2007]上升序列

题意:对于一个给定的S={a1,a2,a3,…,an},若有P={ax1,ax2,ax3,…,axm},满足(x1 < x2 < … < xm)且( ax1 < ax
2 < … < axm)。那么就称P为S的一个上升序列。

有m个询问,每次询问一个长度L,如果没有长度为L的上升序列,输出Impossible,要不然求一个字典序最小的上升序列。

(这题的字典序最小居然指的是下标)

n<=10000,m<=1000

题解:倒着dp,用线段树求出每个点和它后面最长的上升序列的长度。

然后构造的时候,从1开始,如果f[1]>=L 输出f[1],并且 L--   .......以此类推,可以保证是字典序最小的。

复杂度nlogn+nm

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 16384
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}

int n,cnt=0,m;
int l[10005],s[10005],f[10005];
int T[N*2+5];

void renew(int x,int ad)
{
    x+=N;T[x]=max(T[x],ad);
    for(x>>=1;x;x>>=1)T[x]=max(T[x<<1],T[(x<<1)+1]);
}

int query(int l,int r)
{
    int sum=0;if(l>n) return 0;
    for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1) sum=max(sum,T[l+1]);
        if( r&1) sum=max(sum,T[r-1]);
    }
    return sum;
}

int main()
{
    n=read();for(int i=1;i<=n;i++) s[i]=l[i]=read();
    sort(l+1,l+n+1);
    for(int i=1;i<=n;i++)if(l[i]!=l[i-1])l[++cnt]=l[i];
    for(int i=n;i;i--)
    {
        int x=lower_bound(l+1,l+cnt+1,s[i])-l;
        f[i]=query(x+1,cnt)+1;
        renew(x,f[i]);
    }
    int maxn=query(1,cnt);m=read();
    for(int i=1;i<=m;i++)
    {
        int x=read();if(x>maxn){puts("Impossible");continue;}
        for(int j=1,pre=0;x;j++)
            if(f[j]>=x&&s[j]>pre)
            {printf("%d",s[j]);x--;if(x)printf(" ");pre=s[j];}
        puts("");
    }
    return 0;
}

 

posted @ 2017-03-01 21:40  FallDream  阅读(188)  评论(0编辑  收藏  举报