P1439 【模板】最长公共子序列
这个题我们使用朴素算法肯定是过不了的,时间会超,内存也会超
#include<iostream>
using namespace std;
const int N=1005;
int a[N],b[N],dp[N][N];
signed main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
cin>>b[i];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(a[i]==b[j])
dp[i][j]=dp[i-1][j-1]+1;
else
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
cout<<dp[n][n]<<endl;
}
我们就需要对算法进行优化
用题解大佬的话来说就是离散化输入
A:3 2 1 4 5
B:1 2 3 4 5
我们不妨给它们重新标个号:把3标成a,把2标成b,把1标成c……于是变成:
A: a b c d e
B: c b a d e
这样就变成了一个寻找LIS的问题
关于LIS的大小:我们可以创建一个用来存放找到的LIS的数组f,最后输出数组f的大小就好了
也就是我们在brr数组种不断取寻找为LIS的元素,用brr数组的元素与f数组中当前最大的元素进行对比,如果是大于,就直接放在f数组中,如果不是,就用二分法去找到该元素可以放在f数组的哪一个位置上,不断的增加f数组的大小,最后输出
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100005;
int mod=999999999;
int main(){
int n,len=0,arr[maxn],brr[maxn],f[maxn],map[maxn];
cin>>n;
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++){
cin>>arr[i];
map[arr[i]]=i;
}
for(int i=1;i<=n;i++){
cin>>brr[i];
f[i]=mod;
}
f[0]=0;
for(int i=1;i<=n;i++){
int l=0,mid=0,r=len;
if(map[brr[i]]>f[len]){
f[++len]=map[brr[i]];
}
else{
while(l<r){
mid=(l+r)/2;
if(f[mid]>map[brr[i]])
r=mid;
else
l=mid+1;
}
f[l]=min(map[brr[i]],f[i]);
}
}
cout<<len;
return 0;
}