洛谷 P1439 【模板】最长公共子序列(DP,LIS?)

题目描述

给出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

Solve

首先,来看一下 N 2 N^2 N2的算法:
d p [ i ] [ j ] = { m a x ( d p [ i ] [ j ] , d p [ i − 1 ] [ j − 1 ] + 1 ) a [ i ] = = b [ j ] m a x ( d p [ i ] [ j − 1 ] , d p [ i − 1 ] [ j ] ) a [ i ] ! = b [ j ] dp[i][j]=\left\{ \begin{array}{rcl} max(dp[i][j],dp[i-1][j-1]+1) & & {a[i]==b[j]}\\ max(dp[i][j-1],dp[i-1][j]) & & {a[i]!=b[j]} \end{array} \right. dp[i][j]={max(dp[i][j],dp[i1][j1]+1)max(dp[i][j1],dp[i1][j])a[i]==b[j]a[i]!=b[j]
d p [ i ] [ j ] dp[i][j] dp[i][j]代表 a a a数组的前 i i i位与 b b b数组的前 j j j位的最长公共子序列的长度

d p [ 0 ] [ 0 ] = ( a [ 0 ] = = b [ 0 ] ) dp[0][0]=(a[0]==b[0]) dp[0][0]=(a[0]==b[0])

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


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

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

例如: a = { 3 , 1 , 2 , 4 , 5 } ; b = { 1 , 3 , 2 , 4 , 5 } a=\{3,1,2,4,5\};b=\{1,3,2,4,5\} 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 a a进行处理后的数组为 { 0 , 1 , 2 , 3 , 4 } \{0,1,2,3,4\} {0,1,2,3,4}

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

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

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

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

Code

/*************************************************************************

	 > Author: WZY
	 > School: HPU
	 > Created Time:   2019-02-08 15:20:18
	 
************************************************************************/
#include 
#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;
}

你可能感兴趣的:(洛谷,DP)