这个算法其实是因为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)的作法。

 #include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
map<int,int>M;
int main()
{ int n,m,p,q,i,k,j,t;
int a[],b[],g[];
//freopen("in.txt","r",stdin);
cin>>t;
for(int test=;test<=t;++test)
{
M.clear();
int x=;
cin>>n>>p>>q;
for(i=;i<=p+;++i)
{
scanf("%d",a+i);
if(!M[a[i]]) M[a[i]]=x++;
}
for(i=;i<=q+;++i)
{
scanf("%d",b+i);
b[i]=M[b[i]];
}
memset(g,inf,sizeof(g));
for(i=;i<=q+;++i)
{
*lower_bound(g,g+,b[i])=b[i];
}
printf("Case %d: %d\n",test,(int)(lower_bound(g,g+,inf)-g));
}
return ;
}

再来看一道,

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

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

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

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

 #include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
map<int,int>M;
int x[];
int g[];
int main()
{ int n,m,p,q,i,k,j,t;
while(cin>>n){int a[];p=;
for(i=;i<=n;++i)
{
for(j=;j<=;++j)
{
scanf("%d",a+j);
}sort(a+,a++,greater<int>());
for(int di=;di<=;++di)
{
if(a[di]==a[di-]) continue;
x[p++]=a[di];
}
}
memset(g,inf,sizeof(g));
for(i=;i<p;++i)
*lower_bound(g,g+p+,x[i])=x[i];
cout<<(lower_bound(g,g+p+,inf)-g)<<endl;
}
return ;
}

LCS 的 NlogN作法的更多相关文章

  1. LIS与LCS的nlogn解法

    LIS(nlogn) #include<iostream> #include<cstdio> using namespace std; ; int a[maxn]; int n ...

  2. O(nlogn)实现LCS与LIS

    序: LIS与LCS分别是求一个序列的最长不下降序列序列与两个序列的最长公共子序列. 朴素法都可以以O(n^2)实现. LCS借助LIS实现O(nlogn)的复杂度,而LIS则是通过二分搜索将复杂度从 ...

  3. uva 10635 LCS转LIS

    这道题两个数组都没有重复的数字,用lcs的nlogn再适合不过了 #include <iostream> #include <string> #include <cstr ...

  4. 【CZY选讲·扩展LCS】

    题目描述 给出两个仅有小写字母组成的字符串str1 和str2,试求出两个串的最长公共子序列. 数据范围 |str1| ⩽ 1000; |str2| ⩽ 10^6 题解:    ①直接进行LCS( ...

  5. NYIST 760 See LCS again

    See LCS again时间限制:1000 ms | 内存限制:65535 KB难度:3 描述There are A, B two sequences, the number of elements ...

  6. OI总结

    当下考的钟声叮当响起,该走了,一年半的OI竞赛就此结束 留下了很多遗憾.也拥有过一段美好的竞赛生活 结识了一群优秀的OI战友,一起进步一起开心一起忧愁,但这一切的一切都将在今晚变成过去式,CSp的好与 ...

  7. dp--最长上升子序列LIS

    1759:最长上升子序列 总时间限制:  2000ms 内存限制:  65536kB 描述 一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的.对 ...

  8. 动态规划 Dynamic Programming 学习笔记

    文章以 CC-BY-SA 方式共享,此说明高于本站内其他说明. 本文尚未完工,但内容足够丰富,故提前发布. 内容包含大量 \(\LaTeX\) 公式,渲染可能需要一些时间,请耐心等待渲染(约 5s). ...

  9. O(nlogn)LIS及LCS算法

    morestep学长出题,考验我们,第二题裸题但是数据范围令人无奈,考试失利之后,刻意去学习了下优化的算法 一.O(nlogn)的LIS(最长上升子序列) 设当前已经求出的最长上升子序列长度为len. ...

随机推荐

  1. PHP数组遍历详解

    一.PHP数组简介 1.PHP数组的分类 按照下标的不同分为关联数组和索引数组①索引数组:下标从0开始依次增长②关联数组:下标为字符串格式,每个下标字符串与数组的值一一对应,(有点像对象的键值对) 下 ...

  2. django博客项目9

    ................

  3. Django - 权限(4)- queryset、二级菜单的默认显示、动态显示按钮权限

    一.queryset Queryset是django中构建的一种数据结构,ORM查询集往往是queryset数据类型,我们来进一步了解一下queryset的特点. 1.可切片 使用Python 的切片 ...

  4. 采购订单打印并预览PDF

    *&---------------------------------------------------------------------* *& Report Z01MMF019 ...

  5. APP中关于Android和IOS与网页交互

    安卓交互: //安卓js代码start function bntcat(){ if(isAndroid){ musicPause() } var str = '{"tips":20 ...

  6. Linux启动应用(比如jmeter)报An error occurred: Can't connect to X11 window server using ':0.0' as the value of the DISPLAY variable.

    Linux启动应用(比如jmeter)报An error occurred: Can't connect to X11 window server using ':0.0' as the value ...

  7. 安装vue-cli脚手架

    一.安装node.js 1.什么是node.js? Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境. Node.js 使用了一个事件驱动.非阻塞式 I/O 的模 ...

  8. beego——flash数据

    这个flash与 Adobe/Macromedia Flash没有任何关系,它主要用于在两个逻辑间传递临时数据, flash中存放的所有数据会在紧接着的下一个逻辑中调用后清除. 一般用于传递提示和错误 ...

  9. 简单的menu和点击(包括alertDialog定制)

    import android.app.Activity;import android.app.AlertDialog;import android.app.Dialog;import android. ...

  10. Codeforces Round #304 (Div.2)

    A. Soldier and Bananas 题意:有个士兵要买w个香蕉,香蕉起步价为k元/个,每多买一个则贵k元.问初始拥有n元的士兵需要借多少钱? 思路:简单题 #include<iostr ...