P1439 【模板】最长公共子序列 题解

CSDN同步

原题链接

简要题意:

给定两个 \(1\) ~ \(n\) 的排列,求其 最长公共子序列

嗯,下面给出若干算法吧。

算法一

不管它是 \(1\) ~ \(n\) 的排列这一性质。

求 \(\text{LCS}\)(即最长公共子序列)的套路方法:

用 \(f_{i,j}\) 表示 \(a_1\) ~ \(a_i\) 和 \(b_1\) ~ \(b_j\) 的最长公共子序列。那么不考虑边界问题,则存在:

\[f_{i,j} = \begin{cases} f_{i-1,j-1}+ 1 , a_i = b_j \\max(f_{i,j-1} , f_{i-1,j}) \end{cases}\]

显然,当前位相等则一起缩,否则一个缩。

时间复杂度:\(O(n^2)\).

实际得分:\(50pts\).

算法二

嗯,你去百度上搜了一下 \(\text{LCS}\) 的求法,然后发现最优的 \(\text{dp}\) 就是 \(O(n^2)\)?

但是注意到一个性质 ,两个数组都是 \(1\) ~ \(n\) 的排列。

所以今天我们要秀出什么操作呢!

5
3 2 1 4 5
1 2 3 4 5

嗯,如果我们把 3 2 1 4 5 变成 1 2 3 4 5,即建立一种关系为:

3 - 1
2 - 2
1 - 3
4 - 4
5 - 5

然后 1 2 3 4 5 它就变成了 3 2 1 4 5 (这纯属巧合啊)。

你发现,通过这样一波操作,其实 \(\text{LCS}\) 本质就是 在 \(b_i\) 中找到若干个在 \(a_i\) 中有序出现的子序列。

显然一波操作之后 \(a_i\) 有序,然后就是直接求 \(b_i\) 的 \(\text{LIS}\)(最长上升子序列)即可。因为任意的两个 \(x < y\) 显然对应的 \(a_i\) 也满足有该序列。

时间复杂度:\(O(n \log n)\).

实际得分:\(100pts\).

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;

const int N=1e5+1;

inline int read(){char ch=getchar();int f=1;while(ch<‘0‘ || ch>‘9‘) {if(ch==‘-‘) f=-f; ch=getchar();}
	int x=0;while(ch>=‘0‘ && ch<=‘9‘) x=(x<<3)+(x<<1)+ch-‘0‘,ch=getchar();return x*f;}

int a2[N],a1[N],be[N];
int b[N],f[N],ans,n;

int main(){
	n=read(); for(int i=1;i<=n;i++)
		a1[i]=read(),be[a1[i]]=i; //建立对应关系
	for(int i=1;i<=n;i++) a2[i]=read();
	for(int i=1;i<=n;i++) {
		if(be[a2[i]]>b[ans]) { //正常套路 LIS
			b[++ans]=be[a2[i]]; f[i]=ans; continue;
		} int t=lower_bound(b+1,b+1+ans,be[a2[i]])-b;
		b[t]=be[a2[i]]; f[i]=t;
	} printf("%d\n",ans);
	return 0;
}

原文地址:https://www.cnblogs.com/bifanwen/p/12676102.html

时间: 2024-10-07 02:02:07

P1439 【模板】最长公共子序列 题解的相关文章

模板 最长公共子序列

[模板]最长公共子序列 1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 6 char s1[1000],s2[1000]; 7 int len1,len2,dp[1000][1000],mark[1000][1000];//如果数据太大,dp数组可以考虑滚动数组 8 9 void LCS() 10 { 11 int i,j; 12 mem

P2516 [HAOI2010]最长公共子序列 题解(LCS)

题目链接 最长公共子序列 解题思路 第一思路: 1.用\(length[i][j]\)表示\(a\)串的前\(i\)个字符与\(b\)串的前\(j\)个字符重叠的最长子串长度 2.用\(num[i][j]\)表示 \(a\)串的前\(i\)个字符与\(b\)串的前\(j\)个字符重叠的最长子串个数 则求\(length[i][j],num[i][j]\)时有以下递推关系: \(length[i][j]:\) 如果当前两串结尾字符相等,则\(length[i][j]=length[i-1][j-1

洛谷 P1439 【模板】最长公共子序列

神TM模板..我本来想休闲一下写点水题的... 开始做的时候直接敲了一个O(N2)的算法上去,编译的时候才发现根本开不下.. 好了,谈回这道题. 先不加证明的给出一种算法. 若有一组数据 2 4 2 5 1 3 2 5 4 1 3 那么我们令 4 2 5 1 3 | | | | | 1 2 3 4 5 第三行的数据就变成 2 3 1 4 5 很明显,答案是这个数据的最长上升子序列,即4 == 2 3 4 5,即原数列的2 5 1 3. 现在来大概的介绍一下这样做的原因. 首先,观察题目,注意到这

【luogu1439】 【模板】最长公共子序列 [动态规划][LIS最长上升子序列][离散化]

P1439 [模板]最长公共子序列 此思路详见luogu第一个题解 一个很妙的离散化 刘汝佳蓝书上面的LIS 详见蓝书 d[i]以i为结尾的最长上升子序列的长度     g[i]表示d值为i的最小状态的编号即长度为i的上升子序列的最小末尾值 1 for(int i=1;i<=n;++i) scanf("%d",&a[i]); 2 for(int i=1;i<=n;++i) 3 { 4 int k=lower_bound(g+1,g+1+n,a[i])-g; 5 d[

Luogu 1439 【模板】最长公共子序列

题目描述 给出1-n的两个排列P1和P2,求它们的最长公共子序列. 输入输出格式 输入格式: 第一行是一个数n, 接下来两行,每行为n个数,为自然数1-n的一个排列. 输出格式: 一个数,即最长公共子序列的长度 输入输出样例 输入样例#1: 5 3 2 1 4 5 1 2 3 4 5 输出样例#1: 3 说明 [数据规模] 对于50%的数据,n≤1000 对于100%的数据,n≤100000 [题解] 首先不难想到的是将其转化成一个序列的最长上升子序列 由于两个序列均为1~n的排列,在将其中一个

POJ 1458 - Common Subsequence(最长公共子序列) 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:http://poj.org/problem?id=1458 题目大意: 有若干组数据,每组给出两个字符串(中间用任意数量的空格间隔),输出这两个字符串最长公共子序列的长度.每次输出后换行. 分析: 动态规划求LCS,f[i][j]表示第一个字符串匹配到第i位,第二个字符串匹配到第j位时最长公共子序列的长度. 转移方程:当a[i] = b[i]时,f[i][j] = f[i-1][j-1]+1,其他情况时f[i][j

【基础练习】【线性DP】codevs1408 最长公共子序列(上升)题解

</pre><p></p><p style="color:rgb(54,46,43); font-family:Arial; font-size:14px; line-height:26px"><span style="line-height:24px; text-indent:28px">这道题目捣鼓了一个小时了终于弄出来咯···怒吼三声:容易吗!文章被盗还是很严重,加版权信息转载请注明出处 [ameta

【模板】最长公共子序列(二维偏序)

给出1-n的两个排列P1和P2,求它们的最长公共子序列. 洛谷1439 1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int maxn=100010; 5 int n,x,ans,tmp,pos[maxn],t[maxn]; 6 void read(int &k){ 7 k=0; int f=1; char c=getchar(); 8 while(c<'0'||c>

51Nod - 1006 最长公共子序列Lcs模板

给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdkscab ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最长的子序列. Input 第1行:字符串A 第2行:字符串B (A,B的长度 <= 1000)Output输出最长的子序列,如果有多个,随意输出1个. Sample Input abcicba abdkscab Sample Output abca 只能求最长公共子序列的长度,不能输出这个串是什么