洛谷p1439 最长公共子序列(绝密!最长公共子序列的本质居然是....)

题目描述

给出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


一开始学dp的时候就接触了最长公共子序列,当时觉得超简单啊,转移方程非常好理解,这几天刷水题的时候看到了立马就写了。但看到数据范围就蒙了= =(maye10^5!!)


但我还是超皮的用dp试了一下,结果就绿了两个点!!其他不是RE就是T( ' – ' ) (凉凉qwq)


下面是n方算法(二维数组都开不下的辣鸡算法QAQ)非常好理解就不多bb了orz



垂死挣扎了很久,还是没想出来nlogn的算法(啊我真菜)。然后看着那个窒息的二十分,我终于忍不住打开了题解。从打开题解到提交然后ac一共就五六分钟吧。


题解里的前排dalao讲的炒鸡清楚/////(以下是copy的dalao的题解。权侵删)


我们可以以第一个串为标准,用第二个串来匹配第一个串,看能匹配多少,所以,其实第一个串的每个数字其实影响不大,只有知道它对应了第二串的哪个数字就好了,那么我们为什么不把他给的串重新定义一下?


比如他的样例:3 2 1 4 5 我们把他变成 1 2 3 4 5 用一个数组记录一下每个数字变成了什么,相当于离散化了一下3-1;2-2;1-3;4-4;5-5;


现在我们的第二串1 2 3 4 5 按我们离散化的表示:3 2 1 4 5


然后就非常容易得到正确做法啦!没错!就是经典的最长不下降子序列(包含上升和相同)!


真的是万万没想到啊唔。总之,疯狂为nb的dalao们打call就对了!!


最后献上我的低龄化代码(〃ω〃)




没p放啦,over!


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <queue>
#define maxi 0x7fffffff
using namespace std;

int n,x,ans;
int a[400000],b[400000],c[400000];

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
	{
		scanf("%d",&x);
		a[x]=i;
	}
	for(int i=1;i<=n;++i)
	{
		scanf("%d",&x);
		b[i]=a[x];
	}
	c[0]=-0x7fffffff;
	for(int i=1;i<=n;++i)
	{
		if(b[i]>=c[ans])
		{
			c[++ans]=b[i];
			continue;
		}
		int l=0,r=ans;
		while(l!=r)
		{
			int mid=(l+r)/2;
			if(b[i]<c[mid])r=mid;
			else l=mid+1;
		}
		c[l]=b[i];
	}
	printf("%d",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40942982/article/details/79414792