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\n",len);
    return 0;
 } 
时间: 2024-10-12 14:53:18

luogu P3402 最长公共子序列的相关文章

P3402 最长公共子序列(nlogn)

P3402 最长公共子序列 题目背景 DJL为了避免成为一只咸鱼,来找Johann学习怎么求最长公共子序列. 题目描述 经过长时间的摸索和练习,DJL终于学会了怎么求LCS.Johann感觉DJL孺子可教,就给他布置了一个课后作业: 给定两个长度分别为n和m的序列,序列中的每个元素都是正整数.保证每个序列中的各个元素互不相同.求这两个序列的最长公共子序列的长度. DJL最讨厌重复劳动,所以不想做那些做过的题.于是他找你来帮他做作业. 输入输出格式 输入格式: 第一行两个整数n和m,表示两个数列的

【luogu 1439 最长公共子序列】

题目描述 给出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 [题解]       ①LCS->LIS       ②树状数组维护nlogn LIS #i

【Luogu】P3402最长公共子序列(LCS-&gt;nlognLIS)

题目链接 SovietPower 的题解讲的很清楚.Map或Hash映射后用nlogn求出LIS.这里只给出代码. #include<cstdio> #include<cctype> #include<map> #include<algorithm> using namespace std; map<int,int> vis; inline long long read(){ long long num=0,f=1; char ch=getcha

Luogu 1439 【模板】最长公共子序列

题目描述 给出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 [题解] 首先不难想到的是将其转化成一个序列的最长上升子序列 由于两个序列均为1~n的排列,在将其中一个

最长公共子序列(luogu 1439)

题目描述 给出1-n的两个排列P1和P2,求它们的最长公共子序列. 输入输出格式 输入格式: 第一行是一个数n, 接下来两行,每行为n个数,为自然数1-n的一个排列. 输出格式: 一个数,即最长公共子序列的长度 输入输出样例 输入样例 5 3 2 1 4 5 1 2 3 4 5 输出样例 3 说明 [数据规模] 对于50%的数据,n≤1000 对于100%的数据,n≤100000 瞬时记忆 O(nlogn) 做法,意思大概是先把一个 a 序列映射到一个数组(似乎是叫做离散化),然后用它-- 代码

【luogu1439】 【模板】最长公共子序列 [动态规划][LIS最长上升子序列][离散化]

P1439 [模板]最长公共子序列 此思路详见luogu第一个题解 一个很妙的离散化 刘汝佳蓝书上面的LIS 详见蓝书 d[i]以i为结尾的最长上升子序列的长度     g[i]表示d值为i的最小状态的编号即长度为i的上升子序列的最小末尾值 1 for(int i=1;i<=n;++i) scanf("%d",&a[i]); 2 for(int i=1;i<=n;++i) 3 { 4 int k=lower_bound(g+1,g+1+n,a[i])-g; 5 d[

最长公共子序列的代码实现

关于最长公共子序列(LCS)的相关知识,http://blog.csdn.net/liufeng_king/article/details/8500084 这篇文章讲的比较好,在此暂时不再详说. 以下是我代码实现两种方式:递归+递推: 1 #include <bits/stdc++.h> 2 using namespace std; 3 int A[100]; 4 int B[100]; 5 6 //int B[]={2,3,5,6,9,8,4}; 7 int d[100][100]={0};

NYOJ 36 &amp;&amp;HDU 1159 最长公共子序列(经典)

链接:click here 题意:tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列. 输入 第一行给出一个整数N(0<N<100)表示待测数据组数 接下来每组数据两行,分别为待测的两组字符串.每个字符串长度不大于1000. 输出 每组测试数据输出一个整数,表示最长公共子序列长度.每组

poj1159 Palindrome(最长公共子序列)

Palindrome Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 52966   Accepted: 18271 Description A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to write a