[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;
}
时间: 2024-12-20 21:00:23

[bzoj1046][HAOI2007]上升序列的相关文章

[BZOJ1046] [HAOI2007] 上升序列 (dp)

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的上升序列

【动态规划】【最长上升子序列】【贪心】bzoj1046 [HAOI2007]上升序列

nlogn求出最长上升子序列长度. 对每次询问,贪心地回答.设输入为x.当前数a[i]可能成为答案序列中的第k个,则若 f[i]>=x-k && a[i]>ans[k-1] 即可. f[i]表示以a[i]开头的最长上升子序列长度. 但这个东西难以统计.so 我们将原序列反序,求f[i] 表示以 a[i]为结尾的最长下降子序列长度即可.最后再将f.a reverse一下. 1 #include<cstdio> 2 #include<algorithm> 3

[BZOJ1046][HAOI2007]上升序列 DP+贪心

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1046 我们先求出对于每一个数字作为开头的LCS的长度f[i],最长的f[i]为mxlen. 对于每一个询问,我们选取答案,从第1个开始选.假设当前已经选到了第x个答案,我们只需要一直往后面找到第一个f[k]且f[k]+x>mxlen,它就是第x+1个答案. 这样时间复杂度就是$O(nm)$的,感觉玄学卡过…… 1 #include<cstdio> 2 #include<cs

BZOJ 1046: [HAOI2007]上升序列 LIS -dp

1046: [HAOI2007]上升序列 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3438  Solved: 1171[Submit][Status][Discuss] Description 对于一个给定的S={a1,a2,a3,…,an},若有P={ax1,ax2,ax3,…,axm},满足(x1 < x2 < … < xm)且( ax1 < ax2 < … < axm).那么就称P为S的一个上升序列.如果有多

【BZOJ】1046 : [HAOI2007]上升序列

1046: [HAOI2007]上升序列 题意:给定S={a1,a2,a3,…,an}问是否存在P={ax1,ax2,ax3,…,axm},满足(x1 < x2 < … < xm)且( ax1 < ax2 < … < axm),若存在多组符合长度为m的递增子序列,则输出以序号字典序最小的:并非是数值 Sample Input 6 3 4 1 2 3 6 3 6 4 5 Sample Output Impossible 1 2 3 6 Impossible 数据范围 N&

【BZOJ 1046】 1046: [HAOI2007]上升序列

1046: [HAOI2007]上升序列 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

1046: [HAOI2007]上升序列(dp)

1046: [HAOI2007]上升序列 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4999  Solved: 1738[Submit][Status][Discuss] Description 对于一个给定的S={a1,a2,a3,…,an},若有P={ax1,ax2,ax3,…,axm},满足(x1 < x2 < … < xm)且( ax1 < ax2 < … < axm).那么就称P为S的一个上升序列.如果有多

【BZOJ 1046】 [HAOI2007]上升序列

1046: [HAOI2007]上升序列 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 2688  Solved: 891 [Submit][Status] Description 对于一个给定的S={a1,a2,a3,-,an},若有P={ax1,ax2,ax3,-,axm},满足(x1 < x2 < - < xm)且( ax1 < ax2 < - < axm).那么就称P为S的一个上升序列.如果有多个P满足条件,那

BZOJ 1046: [HAOI2007]上升序列(LIS)

题目挺坑的..但是不难.先反向做一次最长下降子序列.然后得到了d(i),以i为起点的最长上升子序列,接下来贪心,得到字典序最小. ------------------------------------------------------------------- #include<cstdio> #define rep(i,n) for(int i=0;i<n;++i) using namespace std; const int maxn=10005; const int inf=0