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

Posted bifanwen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1439 模板最长公共子序列 题解相关的知识,希望对你有一定的参考价值。

CSDN同步

原题链接

简要题意:

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

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

算法一

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

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

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

[f_{i,j} = egin{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).

算法二

嗯,你去百度上搜了一下 ( ext{LCS}) 的求法,然后发现最优的 ( ext{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 (这纯属巧合啊)。

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

显然一波操作之后 (a_i) 有序,然后就是直接求 (b_i)( ext{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
",ans);
	return 0;
}

以上是关于P1439 模板最长公共子序列 题解的主要内容,如果未能解决你的问题,请参考以下文章

P1439 模板最长公共子序列

P1439 模板最长公共子序列

P1439 模板最长公共子序列

luogu P1439 模板最长公共子序列

P1439 模板最长公共子序列

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