给出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
首先,来看一下N2N^2N2的算法:
dp[i][j]={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]
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[i−1][j−1]+1)max(dp[i][j−1],dp[i−1][j])a[i]==b[j]a[i]!=b[j]
dp[i][j]dp[i][j]dp[i][j]代表aaa数组的前iii位与bbb数组的前jjj位的最长公共子序列的长度
dp[0][0]=(a[0]==b[0])dp[0][0]=(a[0]==b[0])dp[0][0]=(a[0]==b[0])
用这个方法来写,对于10510^5105的数据来说,时间和空间都是不够用的
题中已经说明了:两个数组均是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
对aaa进行处理后的数组为{0,1,2,3,4}\{0,1,2,3,4\}{0,1,2,3,4}
用在aaa中创建的映射关系,将bbb中的元素替换:
old
1
3
2
4
5
new
1
0
2
3
4
得到的新的bbb数组为:{1,0,2,3,4}\{1,0,2,3,4\}{1,0,2,3,4}
我们可以发现:新的bbb数组的最长上升子序列即为原两个数组的最长公共子序列
/*************************************************************************
> 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;
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章