[Problem Solution] [Template] Longest Common Subsequence (LCS)

Title description

Given two permutations P1 and P2 of 1,2,...,n, find their longest common subsequence.

Input format

The first line is a number n.

In the next two lines, each line has n numbers, which is a permutation of natural numbers 1, 2, ..., n.

Output format

A number, that is, the length of the longest common subsequence.

Sample input and output

Input
5
3 2 1 4 5
1 2 3 4 5
Output
3
Description/Prompt
For 50% data, n≤10^3
For 100% data, n≤10^5

Ideas

For 50% of the data, dynamic programming can be considered. Let dp[i][j] represent the length of the longest common subsequence of the subsequences Ai and Bi.
When Ai = Bi, find the maximum of Ai-1 and Bi-1 Long common subsequence, and then add Ai at the end to get the longest common subsequence of A and B.
When Ai != Bi, solve two subproblems:
1. Find the longest common subsequence of Ai-1 and Bi
2. Find the longest common subsequence of Ai and Bi-1,
and then take the maximum of 1, 2 that
is

Ai=Bi -> dp[i][j]= dp[i-1][j-1]+1

Ai!=Bi -> dp[i][j]=max(dp[i][j-1],dp[i-1][j])

DP code

#include<bits/stdc++.h>
using namespace std;
const int N=2010;
int dp[N][N],a[N],b[N],n;
int main()
{
    
    
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	for (int i=1;i<=n;i++) scanf("%d",&b[i]);
	for (int i=1;i<=n;i++)
	  for (int j=1;j<=n;j++)
	  {
    
    
	  	dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
	  	if (a[i]==b[j])
	  	  dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
	  } 
	  cout<<dp[n][n]<<endl;
	  return 0;
}

Because the above code uses double loops, the time complexity is O(n^2), which is not good for 100% data, so a Luogu boss stepped up and said the following paragraph:

Because the two sequences are full arrays of 1~n, then the elements of the two sequences are different and the same, that is to say, only the positions are different, then we use a map array to show the position of the number of the A sequence in the B sequence ——

Because the longest common subsequence is aligned backwards bitwise, if the position of each element of sequence a in sequence b increases, it means that the number in b is behind the overall position of the number in a, and you can consider Include LCS-then it can be transformed into nlogn to find the LIS in the map array used to record the new position.

Ingeniously convert LCS (longest common subsequence) into LIS (longest increasing subsequence)

Code

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,len,a[N],m[N],b[N],f[N];
int main()
{
    
    
	scanf("%d",&n);
	for (int i=1;i<=n;i++) 
	{
    
    
		scanf("%d",&a[i]);
		m[a[i]]=i;
	}
	for (int i=1;i<=n;i++)
	{
    
    
		scanf("%d",&b[i]);
		f[i]=99999999;
	}
	f[0]=0;
	for (int i=1;i<=n;i++)
	{
    
    
		if (m[b[i]]>f[len]) f[++len]=m[b[i]];
		else
		{
    
    
			/*int l=0,r=len;
			while (l<r)
			{
				int mid=(l+r)/2;
				if (f[mid]>m[b[i]]) r=mid;
				else l=mid+1;
			}
			f[l]=min(m[b[i]],f[l]);*/
			int k=lower_bound(f+1,f+1+len,m[b[i]])-f; //这段代码相当于上面的一串二分查找,就是寻找f[]中第一个大于等于m[b[i]]的数的位置
			f[k]=min(m[b[i]],f[k]);
		} 
	}
	cout<<len<<endl;
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_45485187/article/details/109243027