跳转至

LCS 最长公共子序列

【模板】最长公共子序列

题目描述

给出 \(1,2,\ldots,n\) 的两个排列 \(P_1\)\(P_2\) ,求它们的最长公共子序列。

输入格式

第一行一个整数N,表示我们要将1到N插入序列中。

接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)

输出格式

N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。

100%的数据 n<=100000

  • 对于 \(50\%\) 的数据, \(n \le 10^3\)

  • 对于 \(100\%\) 的数据, \(n \le 10^5\)


我们先设计dp状态,\(f_{i,j}\)表示\(P_1\)\(i\)结尾,\(P_2\)\(j\)结尾时的LCS长度。那么有转移

  • \(P_1[i]=P_2[j]\),那么\(f_{i,j}=f_{i-1-,j-1}+1\)

  • 否则在\(f_{i-1,j},f_{i,j-1}\)中取最大值

实现

两层循环即可。

基本的内容不要忘!

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+5;
int ans,n,p1[MAXN],p2[MAXN],dp[MAXN],web[MAXN];
int main(){
    cin>>n;

    for(int i=1;i<=n;i++){
        cin>>p1[i];web[p1[i]]=i;
    }
    for(int i=1;i<=n;i++){
        cin>>p2[i];dp[i]=0x7f;
    }
    dp[0]=0;
    for(int i=1;i<=n;i++){
        int l=0,r=ans,mid;
        if(web[p2[i]]>dp[ans])dp[++ans]=web[p2[i]];
        else{
            while(l<r){
                mid=(l+r)/2;
                if(dp[mid]>web[p2[i]])r=mid;
                else l=mid+1;
            }
            dp[l]=min(web[p2[i]],dp[l]);
        }

    }
    cout<<ans;
    return 0;
}