山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

洛谷1439 排列LCS问题

洛谷1439 排列LCS问题

本题地址: http://www.luogu.org/problem/show?pid=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 + 二分优化LIS

   首先明确题目的特殊性:序列为1-n的一个排列即一个序列中不存在重复的元素。

   如果LCS正常思路算时间为O(n^2)而且空间需要二维,显然不适用于本题。

   这里将第一个序列a重新编号为1..n,并以这个编号规则重新定义第二个序列b,则问题转化为求新的第二个序列的LIS。

   O(nlogn)求LIS的方法:二分查找。构造一个g数组,g[i]表示d值为i且最小的a值,每次转移求d[i]可以从g中二分查找满足小于a[i]的最大d值,算法在白书上有过探讨(P62)这里不再赘述。

   数据很大,可以考虑优化读入。

 

【代码】

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 const int maxn = 100000+10;
 7 const int INF=1<<30;
 8 int n;
 9 int a[maxn],b[maxn],d[maxn];
10 
11 inline int read_int() {
12     char c; c=getchar();
13     while(!isdigit(c)) c=getchar();
14     
15     int x=0;
16     while(isdigit(c)) {
17         x=x*10+c-'0';
18         c=getchar();
19     }
20     return x;
21 }
22 
23 int main() {
24     n=read_int();
25     int tmp[maxn];
26     for(int i=1;i<=n;i++) a[i]=read_int() , tmp[a[i]]=i;
27     for(int i=1;i<=n;i++) b[i]=read_int() , b[i]=tmp[b[i]];
28     
29     int g[maxn],ans=0;
30     for(int i=1;i<=n;i++) g[i]=INF;
31     for(int i=1;i<=n;i++) {
32         int k=lower_bound(g+1,g+n+1,b[i])-g;
33         d[i]=k;
34         g[d[i]]=b[i];
35         ans=max(ans,d[i]);  //return max
36     }
37     cout<<ans<<"\n";
38     return 0;
39 }

 

posted on 2015-10-21 10:19  hahalidaxin  阅读(584)  评论(0编辑  收藏  举报