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)的作法。
#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作法的更多相关文章
- LIS与LCS的nlogn解法
LIS(nlogn) #include<iostream> #include<cstdio> using namespace std; ; int a[maxn]; int n ...
- O(nlogn)实现LCS与LIS
序: LIS与LCS分别是求一个序列的最长不下降序列序列与两个序列的最长公共子序列. 朴素法都可以以O(n^2)实现. LCS借助LIS实现O(nlogn)的复杂度,而LIS则是通过二分搜索将复杂度从 ...
- uva 10635 LCS转LIS
这道题两个数组都没有重复的数字,用lcs的nlogn再适合不过了 #include <iostream> #include <string> #include <cstr ...
- 【CZY选讲·扩展LCS】
题目描述 给出两个仅有小写字母组成的字符串str1 和str2,试求出两个串的最长公共子序列. 数据范围 |str1| ⩽ 1000; |str2| ⩽ 10^6 题解: ①直接进行LCS( ...
- NYIST 760 See LCS again
See LCS again时间限制:1000 ms | 内存限制:65535 KB难度:3 描述There are A, B two sequences, the number of elements ...
- OI总结
当下考的钟声叮当响起,该走了,一年半的OI竞赛就此结束 留下了很多遗憾.也拥有过一段美好的竞赛生活 结识了一群优秀的OI战友,一起进步一起开心一起忧愁,但这一切的一切都将在今晚变成过去式,CSp的好与 ...
- dp--最长上升子序列LIS
1759:最长上升子序列 总时间限制: 2000ms 内存限制: 65536kB 描述 一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的.对 ...
- 动态规划 Dynamic Programming 学习笔记
文章以 CC-BY-SA 方式共享,此说明高于本站内其他说明. 本文尚未完工,但内容足够丰富,故提前发布. 内容包含大量 \(\LaTeX\) 公式,渲染可能需要一些时间,请耐心等待渲染(约 5s). ...
- O(nlogn)LIS及LCS算法
morestep学长出题,考验我们,第二题裸题但是数据范围令人无奈,考试失利之后,刻意去学习了下优化的算法 一.O(nlogn)的LIS(最长上升子序列) 设当前已经求出的最长上升子序列长度为len. ...
随机推荐
- centos7开机启动tomcat7
1.进入tomcat/bin vi setenv.sh (原来没有这个文件,需要创建出来) 添加 #add tomcat pid CATALINA_PID="$CATALINA_B ...
- Django - 回顾(2)- 中介模型
一.中介模型 我们之前学习图书管理系统时,设计了Publish.Book.Author.AuthorDetail这样几张表,其中Book表和Author表是多对多关系,处理类似这样简单的多对多关系时, ...
- 我的Android进阶之旅------>Android无第三方Jar包的源代报错:The current class path entry belongs to container ...的解决方法
今天使用第三方Jar包afinal.jar时候.想看一下源码,无法看 然后像加入jar相应的源代码包.也无法加入相应的源代码,报错例如以下:The current class path entry b ...
- Java Concurrent happens-before
happens-before relation on memory operations such as reads and writes of shared variables. The resul ...
- 【Navicat连接Oracle数据库】-Navicat连接Oracle数据库设置
1.navicat连接数据配置信息如下图所示: 点击"确定"按钮,进入到软件 按照图中所画的步骤顺序操作,最后重新启动navicat就可. 关于里面的这个文件夹 insta ...
- Django相关介绍
先认识一下MVC框架 MVC的框架模式,即模型M,视图V和控制器C.他们之间以一种插件似的,松耦合的方式连接在一起. Model(模型)是应用程序中用于处理应用程序数据逻辑的部分. 通常模型对象负责在 ...
- disruptor 高并发编程 简介demo
原文地址:http://www.cnblogs.com/qiaoyihang/p/6479994.html disruptor适用于大规模低延迟的并发场景.可用于读写操作分离.数据缓存,速度匹配(因为 ...
- CodeMatic动软自动生成Nhibernate
前两天调查了下自动生成工具MyGeneration和codesmith前一个版本已经不更新了后面一个太高级生成 的代码包含了太多东西,没整明白.不过生成的xmlmapping很强大.所以干脆整合一下c ...
- 用python实现一个计算器
import re def atom_cal(exp): # 计算乘除法 if '*' in exp: a,b = exp.split('*') return str(float(a) * float ...
- 分支语句(switch case)
/switch case 的应用 Console.WriteLine("1.汉堡包"); Console.WriteLine("2.薯条"); Console. ...