luogu1439——【模板】最长公共子序列(DP,LIS?)

题目描述

给出1-n的两个排列P1和P2,求它们的最长公共子序列。

输入输出格式

输入格式:

第一行是一个数n,

接下来两行,每行为n个数,为自然数1-n的一个排列。

输出格式:

一个数,即最长公共子序列的长度

输入输出样例

输入样例#1:

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

输出样例#1:

1
3

说明

【数据规模】

对于50%的数据,n≤1000

对于100%的数据,n≤100000

Solve

首先,来看一下$N^2$的算法:

$dp[i][j]$代表$a$数组的前$i$位与$b$数组的前$j$位的最长公共子序列的长度

$dp[0][0]=(a[0]==b[0])$

用这个方法来写,对于$10^5$的数据来说,时间和空间都是不够用的


题中已经说明了:两个数组均是1-n的排列,即:两个数组的元素是相同的,只是元素所在的位置不同。那么,两个数组的公共子序列中的元素在两个数组中的相对位置是一样的

如果按照下标给第一个数组的元素赋予新的值(按照升序),

例如:$a=\{3,1,2,4,5\};b=\{1,3,2,4,5\}$

old 3 1 2 4 5
new 0 1 2 3 4

对$a$进行处理后的数组为$\{0,1,2,3,4\}$

用在$a$中创建的映射关系,将$b$中的元素替换:

old 1 3 2 4 5
new 1 0 2 3 4

得到的新的$b$数组为:$\{1,0,2,3,4\}$

我们可以发现:新的$b$数组的最长上升子序列即为原两个数组的最长公共子序列

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/*************************************************************************

> Author: WZY
> School: HPU
> Created Time: 2019-02-08 15:20:18

************************************************************************/
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define ms(a,b) memset(a,b,sizeof(a))
#define INF 0x7f7f7f7f
const int maxn=1e6+10;
const int mod=1e9+7;
using namespace std;
int a[maxn];
int b[maxn],b1[maxn];
int vis[maxn];
int dp[maxn];
int main(int argc, char const *argv[])
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
vis[a[i]]=i;
}
for(int i=0;i<n;i++)
{
cin>>b[i];
b1[i]=vis[b[i]];
}
int ans=0;
for(int i=0;i<n;i++)
{
int pos=lower_bound(dp,dp+ans,b1[i])-dp;
dp[pos]=b1[i];
ans=max(ans,pos+1);
}
cout<<ans<<endl;
return 0;
}

本文标题:luogu1439——【模板】最长公共子序列(DP,LIS?)

文章作者:执念

发布时间:2019年02月08日 - 16:02

最后更新:2019年02月14日 - 17:02

原始链接:https://blog.wzy1999.wang/solve/luogu1439/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------本文结束感谢您的阅读-------------
0%