zoukankan      html  css  js  c++  java
  • LIS的O(nlogn)算法

    出自蓝书《算法竞赛入门经典训练指南》

    求最长上升子序列是很常见的可以用动态规划解决的问题……

    很容易根据最优子结构之类的东西得出

    $ ext{dp}[i]$为以第i个数结尾的最长上升子序列长度

    定义$max{emptyset}=0$,粗略地写出

    [ ext{dp}[i] = max left{ ext{dp}[j]|0leqslant j < i,A[j] < A[i] ight} + 1]

    状态数$mathcal{O}({n})$,如果直接枚举转移,转移数$mathcal{O}({n})$,时间复杂度$mathcal{O}({n^2})$

    现在想办法加速转移……

    设$ ext{dp}^{-1}[x]$为$x= ext{dp}[i]$中$ ext{A}[i]$最小的$i$

    设$ ext{pd}[x]= ext{A}[ ext{dp}^{-1}[x]]$

    若有$ ext{A}[i]< ext{A}[j]$且$ ext{dp}[i]== ext{dp}[j]$,那么之后的元素只需要比$ ext{A}[i]= ext{pd}[x]= ext{pd}[ ext{dp}[i]]$大就可以用$ ext{dp}[i]$进行转移

    很容易得[ ext{pd}[1]leqslant ext{pd}[2]leqslant ext{pd}[3]leqslant cdots leqslant ext{pd}[n] ag{1}label{1} ]

    [ ext{dp}[i]=maxleft{x|0leqslant j < i, ext{pd}[x]<A[i] ight}+1]

    即最大的小于A[i]的下标加1,也就等价于最小的大于等于A[i]的下标,设为$k$ $ ag{2}label{2}$

    因为最后$[l,r)$区间收缩到$emptyset$时左侧区间最后一个元素加一就是右侧区间第一个元素

    用STL的lower_bound就不需要自己写二分了

    因为$eqref{1}eqref{2}$,所以$A[i]leqslant ext{pd}[k]$,转移以后需要更新$ ext{pd}[k]$

    但是之前少考虑了$0leqslant j < i$,只需将未计算的$ ext{pd}[x]$设为INF就好了= =

    时间复杂度$mathcal{O}(nlog n)$

    代码

    REPE(i,1,n) pd[i]=INF;
    REP(i,0,n) {
        int k=lower_bound(pd+1,pd+1+n,A[i])-g;
        dp[i]=k;
        pd[k]=A[i];
    }
    

    很容易得最长非降子序列只需将lower_bound改为upper_bound(同样照着二分的参考图)

    然后最长下降子序列只需添加greater<int>()参数,并且初始化为-INF

    注意dp为以第i个数结尾的长度,所以求最长还需求一遍max

  • 相关阅读:
    Mybatis Plus整合PageHelper分页的实现示例
    关于xlrd最新版本不支持.xlsx文件的解决办法
    mysql 错误解决大法 Specified key was too long; max key length is 767 bytes
    php连接redis
    flask通过request.path获取定义view函数的文件和行号
    使用bash内置命令complete来实现参数补全
    linux下对比两个文件夹下python文件的差异
    ssh登录后自动切换到原来的目录
    ssh &2>1 和重定向顺序问题
    wsl1(win10)中安装bochs
  • 原文地址:https://www.cnblogs.com/sahdsg/p/10622662.html
Copyright © 2011-2022 走看看