最长公共子序列 |
Time Limit: 4000ms, Special Time Limit:10000ms, Memory Limit:65536KB |
Total submit users: 50, Accepted users: 36 |
Problem 11313 : No special judgement |
Problem description |
一个数列S,如果分别是两个已知数列的子序列,且是所有符合此条件序列中最长的,则 S 称为这二个序列的最长公共子序列。 Seat26最近很无聊,就去研究最长公共子序列,不过他发现这个问题已经被许多人解决了,没有什么好研究的,他想,要是给定的二个序列没有重复的元素会不会有更好的解法呢? |
Input |
输入有多组数据,每组数据包括三行,第一行有个正整数N,(1<=N<=100000,) 第二,三行有N个数,分别表示第一个数列和第二个数列,每个数列均是1到N的一个排列,最后一行是0,表示输入结束且不需要处理。 最后一行是0,表示输入结束且不需要处理。 |
Output |
对于每一组数据,输出S的长度. |
Sample Input |
3 3 2 1 2 1 3 4 2 1 3 4 3 2 4 1 0 |
Sample Output |
2 2 |
Problem Source |
湖南师范大学第四届大学生计算机程序设计竞赛 |
一般的最长公共子序列都通过动态规划解决的。时间是O(n*n),空间可以优化到O(n)。这题特殊在是1到n的一个组合,就是元素不会出现重复。记录串1在串2中的位置数组a[],a中的最长上升子序列就是答案。
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int N=100005;
int loc[N],a[N];
int stack[N];
#define inf 0x3f3f3f3f
int LIS(int n){
memset(stack,inf,sizeof stack);
for(int i=0;i<n;i++){
int loc=lower_bound(stack,stack+n,a[i])-stack;
stack[loc]=a[i];
}
return lower_bound(stack,stack+n,inf)-stack;
}
int main(){
int n,t;
while(cin>>n&&n){
for(int i=0;i<n;i++){
scanf("%d",&t);
loc[t]=i;//记录值为t的位置
}
for(int i=0;i<n;i++){
scanf("%d",&t);
a[i]=loc[t];//找到值为t的位置放在a中
}
int ans=LIS(n);
printf("%d\n",ans);
}
}