luogu P3402 最长公共子序列

题目背景

DJL为了避免成为一只咸鱼,来找Johann学习怎么求最长公共子序列。

题目描述

经过长时间的摸索和练习,DJL终于学会了怎么求LCS。Johann感觉DJL孺子可教,就给他布置了一个课后作业:

给定两个长度分别为n和m的序列,序列中的每个元素都是正整数。保证每个序列中的各个元素互不相同。求这两个序列的最长公共子序列的长度。

DJL最讨厌重复劳动,所以不想做那些做过的题。于是他找你来帮他做作业。

输入输出格式

输入格式:

第一行两个整数n和m,表示两个数列的长度。

第二行一行n个整数a_1,a_2,…,a_n,保证1≤a_i≤〖10〗^9。

第三行一行m个整数b_1,b_2,…,b_m,保证1≤b_i≤〖10〗^9。

输出格式:

一行一个整数,表示两个数列的最长公共子序列的长度。

输入输出样例

输入样例#1:
6 6
1 3 5 7 9 8
3 4 5 6 7 8
输出样例#1:
4

说明

对于40%的数据,n, m≤3000

对于100%的数据,n, m≤300000

普通N^2算法过不了

考虑nlogn

把a[i]映射成其在a中位置

把b[i]在a[I]中出现的位置做一个映射f

使f数组满足不下降,所求f数组长度即为lcs

#include<map>
#include<cstdio>
#include<algorithm>
using namespace std;
map<int,int>mp;
inline int read()
{
    int x=0;char c=getchar();
    while(c<'0'||c>'9')c=getchar();
    while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar() ;
    return x;
}
int n,m,f[200010];
int ef_search(int l,int r,int x)
{
    while(l<r)
    {
        int mid=l+r>>1;
        if(x<=f[mid])r=mid;
        else l=mid+1;
    }
    return l;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
        mp[read()]=i;
    int len=0;
    for(int pos,i=1;i<=m;i++)
    {
        pos=mp[read()];
        if(!pos)continue;
        if(pos>f[len])f[++len]=pos;
        else {
            f[ef_search(1,len,pos)]=pos;
        }
    }
    printf("%d
",len);
    return 0;
 } 
原文地址:https://www.cnblogs.com/sssy/p/7355879.html