题解 P1439 【【模板】最长公共子序列】
假设ans[i]代表当公共最长子序列长度为i时所需要序列a的长度,那么ans当中,就是一个上升序列,方便二分查找,line[i]表示i这个数字在第一个序列中的位置。
每当读入第二个序列的数字m时,我们就在ans里用二分查找找到ans[r]<line[m]<ans[l],接着就可以将ans[l]的值降低为line[m]的值。当然,如果说ans中最大的数小于line[m],就可以给最长公共子序列长度加一
代码如下:
#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
//freopen("test.cpp","r",stdin);
int n,m,line[100001]={0},ans[100001]={0},total=0;//total表示最长公共子序列长度
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>m;
line[m]=i;//line[m]是m在第一个序列中的位置
}
for(int i=1;i<=n;i++)
{
cin>>m;
int search=line[m];
if(search>ans[total])ans[++total]=search;else
{
int l=0,r=total;
while(l<=r)
{
int mid=ans[(l+r)/2];
if(search<mid)r=(l+r)/2-1;else
l=(l+r)/2+1;
}
ans[l]=search;//因为之前最长公共子序列长度为l时所需要的第一个序列的长度大于长度为l-1时再包括了数字m时(同样最长公共子序列长度为l)所需要第一个序列的长度
}
}
cout<<total;
}