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 }
原文地址:https://www.cnblogs.com/zzqc/p/7326013.html