• P2215 [HAOI2007]上升序列


    传送门

    注意题目要求的字典序最小是指下标最小

    容易想到 $dp$,但是发现正着做不好搞,考虑反过来搞

    原本正着做是求最长上升子序列,反过来就变成求最长下降子序列

    然后我们就可以求出以每个位置为起点的上升子序列的最大长度

    然后直接贪心从前往后枚举即可,复杂度 $O(nm)$

    维护最长下降子序列我是用树状数组搞的

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    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<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=1e5+7;
    int n,m,a[N],b[N],d[N];
    int f[N],t[N];
    inline void add(int x,int v) { while(x<=n) { if(t[x]<v) t[x]=v; x+=x&-x; } }
    inline int ask(int x) { int res=0; while(x) res=max(res,t[x]),x-=x&-x; return res; }
    int main()
    {
        n=read(); int c,mx=0;
        for(int i=1;i<=n;i++) a[i]=d[i]=b[i]=read();
        sort(b+1,b+n+1);
        for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+n+1,a[i])-b;
        for(int i=n;i;i--)
            f[i]=ask(n+2-a[i]-1)+1,add(n+2-a[i],f[i]),mx=max(mx,f[i]);
            //本来树状数组求的是小于某个值的范围,为了求大于某个值的范围,把数变成负的然后统一加一个数就行了
        m=read();
        for(int i=1;i<=m;i++)
        {
            c=read(); if(c>mx) { printf("Impossible
    "); continue; }
            for(int j=1,p=0;j<=n&&c;j++)
                if(f[j]>=c&&p<d[j])
                    p=d[j],printf("%d ",p),c--;
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    虚拟设备 ide1:0 将开始断开
    虚拟机集群启动 某一台启动失败
    jeesite1,工具类,文件介绍
    line-clamp
    js中同名的函数的调用情况
    获取子页面iframe的点击事件及iframe跨域的交互
    Docker环境搭建入门
    软件工程课后作业:论我对百度搜索的看法
    第二阶段第十天12.10
    软件工程:用户场景描述
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11438730.html
Copyright © 2020-2023  润新知