zoukankan      html  css  js  c++  java
  • 再探LIS

    昨天讲课的时候突然想起来LIS还有一个东西没搞懂。

    又去研究了下。

    LIS问题就是要求一个序列中最长不下降或上升子序列,而此问题应用较广,例如很多题会有这样的条件

    对于i,j如果他们可以同时选取,则必有|a[i]-a[j]|  <=  |b[i]-b[j]|  (b[i]<b[j])

    数学化归一下下得到 b[i]-b[j] <= a[i]-a[j] <= b[j]-b[i]

    将i,j各放在一边 有

    a[i]-b[i]  >= a[j]-b[j]…………①,

    a[i]+b[i] <= a[j]+b[j]…………②.

    那么我们按其中一个条件排序,即保证排序后的序列对于任意的i,j(i<j)都有①式或②式成立,然后再按另一个条件求LIS即可求出最多可以取多少个。

    若要知道取几次可以取完,那么 根据 dilworth 定理, 等同于求其反条件(即原来非降现在就是下降)子序列长度。

    那么下面介绍求LIS的几种方法

    法一 O(n^2)暴力dp转移

    令dp[i]表示以ai结尾的最长不下降子序列长度

    则转移方程为dp[i]=max{1,dp[j]+1} a[j]<=a[i]

    则max{dp[i]}就是答案

    法二 对于上面的dp转移,显然可以用树状数组优化

    可以做到(nlogn)

    设有 f[i] 表示以大小为i结尾的不下降子序列的最长长度

    则dp[i]=max{f[j]}+1,j<=h[i];

    max{f[j]}用树状数组维护

    具体如下

     1 int g() {
     2     memset(C,0,sizeof C);
     3     int ans=0;
     4     for(int i=1;i<=n;i++) {
     5         dp[i]=1;
     6         int t=query(h[i])+1;
     7         ans=max(ans,t);
     8         add(h[i],t);
     9     }
    10     return ans;
    11 }

    注意:1.可以不保留dp数组,直接更新ans即可。

    2.如果max{h[i]}过大,则需要离散化

    法三 二分法求LIS O(nlogn)

    设s[i]表示以长度为i的上升子序列的最后一位的最小值。

    则每次可以用a[i]去更新s[i]数组

    显然s数组是不下降的

    1 int h[Maxn],s[Maxn],ans,n;
    2 int f(){
    3     s[ans=0]=-INF;
    4     for(int i=1;i<=n;i++){
    5         int v=h[i];
    6         if(v>s[ans])s[++ans]=v;
    7         else*lower_bound(s+1,s+ans+1,v)=v;
    8     }return ans;
    9 }

    对于第6行得到新的答案,根据s数组的定义,显然正确。

    然后如果v<=s[ans],则此时不能更新ans,但是可以更新s数组,如何更新呢?跟上面一样,我们要找到一个s[i] (< v) 则此时可以用这个s[i]来更新s[i+1],而实际上只有这一个更新是有意义的,因为对于<=i的更新只会使答案更劣,对于i+2及以上的不能保证序列合法。

    更新之后就会更新s[i+1]的值,又s[i]是最大的满足s[i]<v的i,所以s[i+1]必是最小的>=v的值,用lower_bound就好了。

    同理如果要求非降子序列 改成下面这样即可

    1 int h[Maxn],s[Maxn],ans,n=1;
    2 int f(){
    3     s[ans=0]=-INF;
    4     for(int i=1;i<=n;i++){
    5         int v=h[i];
    6         if(v>=s[ans])s[++ans]=v;
    7         else*upper_bound(s+1,s+ans+1,v)=v;
    8     }return ans;
    9 }

    可以发现改了两处,一是第6行的>= 二是lower_bound变成了upper_bound

    请自行思考为什么这样可行

  • 相关阅读:
    用批处理实现映射盘网络盘为固定盘符,请更改冲突的硬盘盘符
    linux下mysql寻找my.cnf顺序
    php写memcached ,c读取乱码问题[转]
    linux下boost安装方法
    解决php soap webservice 用c++ soap调用的问题[转]
    【转载】Servlet生命周期与工作原理
    【转载】深入理解Java多态性
    JSP中几个常用的参数与中文乱码问题
    获取数据库连接
    dom4j简单实例
  • 原文地址:https://www.cnblogs.com/showson/p/4666347.html
Copyright © 2011-2022 走看看