BZOJ1046-[HAOI2007]上升序列


题解:
首先求出以每个数为开头上升序列长度,即倒着做最长下降子序列
然后,把字典序尽量小的放前面
即若要求的序列长度为x,如果以第一个数(字典序最小的数)开头的最长上升子序列大等于x,则将它放在答案第一个,第二个数开头小于x,则舍弃,第三个大于x-1,放答案第二个,以此类推。
C o d e

#include<bits/stdc++.h>
#define N 100005
using namespace std;
int n,m,cnt;
int a[N],f[N],q[N];
void solve(int x)
{
    int last=0;
    for(int i=1;i<=n;i++)
        if(f[i]>=x&&a[i]>last)
        {
            printf("%d",a[i]);
            if(x!=1)printf(" ");
            last=a[i];
            x--;
            if(!x)break;
        }
    printf("\n");
}
int find(int x)
{
    int l=1,r=cnt,ans=0;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(q[mid]>x)ans=mid,l=mid+1;
        else r=mid-1;
    }
    return ans;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=n;i;i--)
    {
        int t=find(a[i]);
        f[i]=t+1;
        cnt=max(cnt,t+1);
        if(q[t+1]<a[i])q[t+1]=a[i];
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int x;
        scanf("%d",&x);
        if(x<=cnt)solve(x);
        else puts("Impossible");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_34531807/article/details/81127310
今日推荐