Luogu P1439

令f[i][j]表示a的前i个元素与b的前j个元素的最长公共子序列

可以得到状态转移方程:

if (a[i]==b[j]) dp[i][j]=dp[i-1][j-1]+1;
dp[i][j]=max(dp[i][j],dp[i-1][j],dp[i][j-1]);

时空复杂度都为O(n2)

对于本题这种做法显然是无法接受的。

我们可以对这个题目进行转化。仔细看题,可以发现a,b两个序列都是1-n的排列。

那么,我们可以利用映射,将a中的数一一映射成为1,2,3,4,5……,n

再把b中的数一一对应更改。由于a中的数是升序的,所以b中的最长上升子序列的长度就是a与b的最长公共子序列。LCS问题就转化成了LIS问题。

例如样例

a的 3 2 1 4 5映射为1 2 3 4 5

则b从1 2 3 4 5变为3 2 1 4 5

结合上面的分析就会变得很容易理解了。

#include<algorithm>
#include<cstdio>
using namespace std;
int n,a[100005],b[100005],k[100005],dp[100005],ans;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
k[a[i]]=i;
}
for (int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
b[i]=k[b[i]];
}
dp[1]=1;
for (int i=2;i<=n;i++)
{
for (int j=1;j<i;j++)
{
if (b[i]>b[j]) dp[i]=max(dp[i],dp[j]+1);
else dp[i]=max(1,dp[i]);
}
}
for (int i=1;i<=n;i++)
ans=max(ans,dp[i]);
printf("%d",ans);
return 0;
}

这个动态规划可以很轻松地写出来,但是我们发现时间还是不够优秀。

那么我们就要对这个算法进行优化。对于LIS问题,有一种广为人知的O(nlogn)的解法。

dp[i]中存储长度为i的LIS的最后一个数。

如果符合单调上升就直接增长长度并记录,否则就利用STL二分查找出dp数组中第一个大于b[i]的位置,替换它。

举个例子,例如 3 6 2 4 7 8

一开始的序列{3},接着变成{3,6}

遇到2之后我们将3替换{2,6},为什么可以进行替换呢?

因为后面还有一个4可以替换掉6,构成一条更优的序列。(保证结尾尽可能小,就能保证序列尽可能优)

如果后面没有4呢?那么也没有关系,因为这个2即使修改了也对答案没有任何影响。

(想一想为什么)

dp[1]=b[1];
len=1;
for (int i=2;i<=n;i++)
{
if (b[i]>dp[len]) dp[++len]=b[i];//记录并增长长度。
else
{
int x=upper_bound(dp+1,dp+1+len,b[i])-dp;
dp[x]=b[i];
//利用STL二分查找出dp数组中第一个大于b[i]的位置,替换它。
} }

完整代码如下:

#include<algorithm>
#include<cstdio>
using namespace std;
int n,a[100005],b[100005],k[100005],dp[100005],ans,len;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
k[a[i]]=i;//映射
}
for (int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
b[i]=k[b[i]];//对应修改
}
dp[1]=b[1];
len=1;
for (int i=2;i<=n;i++)
{
if (b[i]>dp[len]) dp[++len]=b[i];
else
{
int x=upper_bound(dp+1,dp+1+len,b[i])-dp;
dp[x]=b[i];
}
}
printf("%d",len);
return 0;
}

【Luogu P1439】最长公共子序列(LCS)的更多相关文章

  1. Luogu 3402 最长公共子序列(二分,最长递增子序列)

    Luogu 3402 最长公共子序列(二分,最长递增子序列) Description 经过长时间的摸索和练习,DJL终于学会了怎么求LCS.Johann感觉DJL孺子可教,就给他布置了一个课后作业: ...

  2. 1006 最长公共子序列Lcs

    1006 最长公共子序列Lcs 基准时间限制:1 秒 空间限制:131072 KB 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdks ...

  3. 动态规划之最长公共子序列LCS(Longest Common Subsequence)

    一.问题描述 由于最长公共子序列LCS是一个比较经典的问题,主要是采用动态规划(DP)算法去实现,理论方面的讲述也非常详尽,本文重点是程序的实现部分,所以理论方面的解释主要看这篇博客:http://b ...

  4. 编程算法 - 最长公共子序列(LCS) 代码(C)

    最长公共子序列(LCS) 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 给定两个字符串s,t, 求出这两个字符串最长的公共子序列的长度. 字符 ...

  5. C++版 - Lintcode 77-Longest Common Subsequence最长公共子序列(LCS) - 题解

    版权声明:本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. C++版 - L ...

  6. POJ 1458 Common Subsequence(最长公共子序列LCS)

    POJ1458 Common Subsequence(最长公共子序列LCS) http://poj.org/problem?id=1458 题意: 给你两个字符串, 要你求出两个字符串的最长公共子序列 ...

  7. 51Nod 1006:最长公共子序列Lcs(打印LCS)

    1006 最长公共子序列Lcs  基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). ...

  8. 51nod 1006 最长公共子序列Lcs 【LCS/打印path】

    1006 最长公共子序列Lcs  基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). ...

  9. 每日一题-——最长公共子序列(LCS)与最长公共子串

    最长公共子序列(LCS) 思路: 代码: def LCS(string1,string2): len1 = len(string1) len2 = len(string2) res = [[0 for ...

  10. 51nod 1006:最长公共子序列Lcs

    1006 最长公共子序列Lcs 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). ...

随机推荐

  1. Apache 4.x HttpClient

    public static Map callRequest(String requestUrl, Method method, Map<String, String> data) thro ...

  2. 函数基础(二)(day11整理)

    目录 昨日内容 函数的定义 函数的三种定义方式 空函数 有参函数 无参函数 函数的调用 函数的返回值 函数的参数 形参 实参 今日内容 可变长参数 可变长形参 可变长实参(仅作了解) 函数对象 函数嵌 ...

  3. 存储路径与文件目录操作ZT

    转自:https://www.cnblogs.com/zrr-notes/p/5953445.html (一)基本存储位置 我们的app在手机中存放的路径是:/var/mobile/Applicati ...

  4. 永恒之蓝复现(win7/2008)

    Kali对Windows2008/7的MS17010漏洞测试(MSF自带模块) 0x01 说明 其实这个MSF自带的exp模块还是挺让人伤脑筋的,因为它支持的OS并不是很多,也就Windows Ser ...

  5. 用js和css实现选项卡效果+jq(2019-10-09)

    1效果图: 2代码: html: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"& ...

  6. [UWP]为番茄钟应用设计一个平平无奇的状态按钮

    1. 为什么需要设计一个状态按钮 OnePomodoro应用里有个按钮用来控制计时器的启动/停止,本来这应该是一个包含"已启动"和"已停止"两种状态的按钮,但我 ...

  7. Java 博客系统 Tale

    Tale Tale的英文含义为故事,我相信每个坚持写Blog的人都是有故事的:中文你叫它 塌了 也无所谓 . Tale 使用了轻量级mvc框架 Blade 开发,默认主题使用了漂亮的 pinghsu, ...

  8. Go 基础学习笔记(3)| 第一个程序 “helloworld”

       //第一个程序总要说的清楚才行.   //建议先运行起第一个程序实践后,再看后面的具体解答 一.helloworld 编写运行 1.编写源程序,在 ~ /hello/src  编写hello.g ...

  9. 关于mysql驱动cj与不是cj的问题

    1. 带cj的是mysql驱动6.0以上的,不带的是6.0以下的. 2.6.0以上的需要注意有时区纠正

  10. Docker(二) Dockerfile 使用介绍

    前言 图解Docker 镜像.容器和 Dockerfile 的关系: 一.Dockerfile的概念 Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序.库.资源.配置等文件外,还包 ...