P3402 最长公共子序列(nlogn)

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方的算法,这道题显然过不去,并且这道题每个数字只出现一次,可以用一个“nlogn”的算法,(加引号的)这个算法只适用于A和B中每个数出现的次数是一个很小的数,这一点题目刚好满足。

具体呢,就是对于在B序列中的元素x,我们在A中找到x的出现位置(在A中的位置)并按降序写下来。然后B中的所有x都有对应的数字,这些数字就是序列C,对C求最长不下降子序列。得到的答案即为A和B的LCS长度。

举个栗子:A={c,a,b,e,d,a,b},B={a,d,c,a,d,b},C={6,2, 5, 1, 6,2, 5, 7,3}

比如B中的a他在A中出现的位置是2,6,按降序后就是6,2;其他的同理。

因为求最长不下降子序列有(nlogn)的算法(http://www.cnblogs.com/mjtcn/p/7197034.html),所以,这也就是nlogn的算法了,再加上预处理出,

这个题这样差不多就完成了,但是,为了方便用map写的,洛谷上只过了7个点,改读入优化,加上inline就过了,可以用哈希写,比map快多了

code

 1 #include<cstdio>
 2 #include<map>
 3 #include<algorithm>
 4
 5 using namespace std;
 6 const int MAXN = 300100;
 7 int f[MAXN];
 8
 9 map<int,int>p;
10 inline int read()
11 {
12     int x = 0;char ch = getchar();
13     while (ch<‘0‘||ch>‘9‘) ch = getchar();
14     while (ch>=‘0‘&&ch<=‘9‘) x = x*10+ch-‘0‘,ch = getchar() ;
15     return x;
16 }
17 inline int search(int l,int r,int x)
18 {
19     while (l<r)
20     {
21         int mid = (l+r)>>1;
22         if (x<=f[mid]) r = mid;
23         else l = mid+1;
24     }
25     return l;
26 }
27 int main()
28 {
29     int n = read(),m = read(),len = 0;
30     for (int x,i=1; i<=n; ++i)
31         x = read(),p[x] = i;
32     for (int a,x,i=1; i<=m; ++i)
33     {
34         a = read();
35         x = p[a];
36         if (!x) continue;
37         if (x>f[len]) f[++len] = x;
38         else
39         {
40             int p = search(1,len,x);
41             f[p] = x;
42         }
43     }
44     printf("%d",len);
45     return 0;
46 }
时间: 2024-10-14 11:55:38

P3402 最长公共子序列(nlogn)的相关文章

最长公共子序列 nlogn

先来个板子 #include<bits/stdc++.h> using namespace std; const int N = 1e6+20, M = 1e6+10, mod = 1e9+7, inf = 1e9+1000; typedef long long ll; struct node { int c; int num; } u[N]; int i,j,k = 0,n,m,x,y = 0,T = 0,ans = 0,big = 0,cas = 0,num = 0,len = 0; bo

luogu P3402 最长公共子序列

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

【算法】最长公共子序列(nlogn)

转载注明出处:http://blog.csdn.net/wdq347/article/details/9001005 最长公共子序列(LCS)最常见的算法是时间复杂度为O(n^2)的动态规划(DP)算法,但在James W. Hunt和Thomas G. Szymansky 的论文"A Fast Algorithm for Computing Longest Common Subsequence"中,给出了O(nlogn)下限的一种算法. 定理:设序列A长度为n,{A(i)},序列B长

【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

UVA 10635--Prince and Princess+nlgn求最长公共子序列

题目链接:点击进入 刚看到这题目还以为又碰到水题了,结果写了个O(n^2)的代码交上去超时了,才发现n有250*250那么大.后面在网上找到了一个nlgn求最长上升子序列的方法,才过了.这个nlgn算法的主要思想是将最长公共子序列转成最长上升子序列,然后用最长上升子序列nlgn的算法求解.更具体的解释可以参看这篇博文:最长公共子序列(nlogn) 代码如下: #include<iostream> #include<cstring> #include<cstdio> #i

Longest Common Substring(最长公共子序列)

Longest Common Substring Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 37 Accepted Submission(s): 28   Problem Description Given two strings, you have to tell the length of the Longest Common Su

LIS LCS 最长上升子序列 最长公共子序列 ...

最长上升子序列,问题定义:http://blog.csdn.net/chenwenshi/article/details/6027086 代码: public static void getData( char[] L ) { int len = L.length; int[] f = new int[len]; String[] res = new String[len]; for( int i = 1; i < len; i++ ) { f[i] = 1; res[i] = "&quo

最长递增子序列 &amp;&amp; 最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离

http://www.cppblog.com/mysileng/archive/2012/11/30/195841.html 最长递增子序列问题:在一列数中寻找一些数,这些数满足:任意两个数a[i]和a[j],若i<j,必有a[i]<a[j],这样最长的子序列称为最长递增子序列. 设dp[i]表示以i为结尾的最长递增子序列的长度,则状态转移方程为: dp[i] = max{dp[j]+1}, 1<=j<i,a[j]<a[i]. 这样简单的复杂度为O(n^2),其实还有更好的方

最长公共子序列问题---动态规划

最长递增子序列问题是一个很基本.较常见的小问题,但这个问题的求解方法却并不那么显而易见,需要较深入的思考和较好的算法素养才能得出良好的算法.由于这个问题能运用学过的基本的算法分析和设计的方法与思想,能够锻炼设计较复杂算法的思维,我对这个问题进行了较深入的分析思考,得出了几种复杂度不同算法,并给出了分析和证明. 一,    最长递增子序列问题的描述 设L=<a1,a2,…,an>是n个不同的实数的序列,L的递增子序列是这样一个子序列Lin=<aK1,ak2,…,akm>,其中k1&l