zoukankan      html  css  js  c++  java
  • LCS 的 NlogN作法

    这个算法其实是因为LIS有NlogN的作法,把LCS转化为了LIS来做。

    对于序列A{},B{},我们可以记录下来B中的每个元素在A中出现的位置,按顺序保存在一个新序列当中,

    如果有多个位置按倒序写,没有就不用写,然后对这个新序列求一个LIS就是两个序列的LCS长度。

    为什么这样可行呢,我们可以这样考虑,对于A序列,下标编号记为1---n1,B和A的最长公共子序列在A中对应的编号肯定是递增的,

    所以B中的这些元素对应的A的编号也是递增的,为了重复计算当有多个编号时倒序存入,表示只能选一个,尽管有多个编号但在B中这只是一个元素。

    A={3,9,7,10,3}   B={5,3,7,3}

    列出B对应的A中的编号(1--5)

    5:无

    3:1,5

    7:3

    3:1,5

    如果按照15315来计算的话相当于B中的一个3当做了两个,但其实并不是,所以应是51351,LIS是1,3,5,也就是A中的3,7,3

    https://vjudge.net/problem/UVA-10635

    很脑洞的一道题,看似再考LCS实则要用LIS写才能不超时。

    题意,给出两个序列A,B,长度分别是p+1和q+1,且A[1]=B[1]=1,A中的元素各不相同B也一样,长度不超过250^2,求AB的LCS。

    用求LCS的方法算复杂度O(pq)肯定超时,由于元素都不相同,我们将A中的元素编号为1~p+1,在B中将A中出现过的元素改为对应的编号,没出现的编号为0(也可以删除)

    然后的任务就是在B中找一个LIS,利用二分查找减小复杂度。

    这其实就是一种LCS的O(NlogN)的作法。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define inf 0x3f3f3f3f
     4 map<int,int>M;
     5 int main()
     6 {
     7 
     8     int n,m,p,q,i,k,j,t;
     9     int a[66000],b[66000],g[66000];
    10     //freopen("in.txt","r",stdin);
    11     cin>>t;
    12     for(int test=1;test<=t;++test)
    13     {
    14         M.clear();
    15         int x=1;
    16         cin>>n>>p>>q;
    17         for(i=1;i<=p+1;++i)
    18         {
    19             scanf("%d",a+i);
    20             if(!M[a[i]]) M[a[i]]=x++;
    21         }
    22         for(i=1;i<=q+1;++i)
    23         {
    24             scanf("%d",b+i);
    25             b[i]=M[b[i]];
    26         }
    27         memset(g,inf,sizeof(g));
    28         for(i=1;i<=q+1;++i)
    29         {
    30             *lower_bound(g,g+65000,b[i])=b[i];
    31         }
    32         printf("Case %d: %d
    ",test,(int)(lower_bound(g,g+65000,inf)-g));
    33     }
    34     return 0;
    35 }

    再来看一道,

    http://www.ifrog.cc/acm/problem/1097

    回忆起B在A中只有一个对应的点时,当时一直按得LIS来做但仔细想一想要求的不就是A和B的LCS吗,原来我早就写过nlogn的LCS做法竟然没有意识到。

    这个问题相当于B中每个元素对应A中的多个元素,所以将匹配的A的编号记录下来做一次LIS就是答案,处理时依然要倒序插入。

    倒序的好处在于如果选那么肯定只出现一个要么就不出现,不会产生一个B对应了多个A。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define inf 0x3f3f3f3f
     4 map<int,int>M;
     5 int x[600100];
     6 int g[600100];
     7 int main()
     8 {
     9 
    10     int n,m,p,q,i,k,j,t;
    11     while(cin>>n){int a[10];p=0;
    12         for(i=1;i<=n;++i)
    13         {
    14             for(j=1;j<=6;++j)
    15             {
    16                scanf("%d",a+j);
    17             }sort(a+1,a+1+6,greater<int>());
    18            for(int di=1;di<=6;++di)
    19            {
    20                if(a[di]==a[di-1]) continue;
    21                x[p++]=a[di];
    22            }
    23         }
    24         memset(g,inf,sizeof(g));
    25         for(i=0;i<p;++i) 
    26             *lower_bound(g,g+p+1,x[i])=x[i];
    27         cout<<(lower_bound(g,g+p+1,inf)-g)<<endl;
    28     }
    29     return 0;
    30 }
  • 相关阅读:
    2020年MongoDB 企业应用实战 基础 复制集 分片集群
    2020年Redis5.0 从入门到企业应用实战
    2020年Jumpserver1.5.8企业生产部署指南
    python单例与数据库连接池
    python 异常处理
    python 正则
    python 多线程
    python 队列
    python 闭包与装饰器
    程序员面试资源集锦
  • 原文地址:https://www.cnblogs.com/zzqc/p/7326013.html
Copyright © 2011-2022 走看看