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

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

  • 相关阅读:
    URAL 2046 A
    URAL 2056 Scholarship 水题
    Codeforces Gym 100286I iSharp 水题
    Codeforces Gym H. Hell on the Markets 贪心
    Codeforces Gym 100286G Giant Screen 水题
    Codeforces Gym 100286B Blind Walk DFS
    Codeforces Gym 100286F Problem F. Fibonacci System 数位DP
    Codeforces Gym 100286A. Aerodynamics 计算几何 求二维凸包面积
    Codeforces Gym 100418K Cards 暴力打表
    Codeforces Gym 100418J Lucky tickets 数位DP
  • 原文地址:https://www.cnblogs.com/showson/p/4666347.html
Copyright © 2011-2022 走看看