洛谷p1439 最长公共子序列(绝密!最长公共子序列的本质居然是....)
题目描述
给出1-n的两个排列P1和P2,求它们的最长公共子序列。
输入输出格式
输入格式:
第一行是一个数n,
接下来两行,每行为n个数,为自然数1-n的一个排列。
输出格式:
一个数,即最长公共子序列的长度
输入输出样例
说明
【数据规模】
对于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; }