P1439 【模板】最长公共子序列
思路:经典dp题,可以将第一序列离散化到第二序列,转化为最长上升子序列问题。
具体为样例 3-1 2-2 1-3 4-4 5-5,则 1 2 3 4 5 转化为 3 2 1 4 5 ,找到这个序列的最长上升子序列即为最长公共序列。
最长上升子序列 一般两种做法
1.直接枚举,枚举到第i项时,枚举第i项前的数,当a[j]<a[i],更新dp[i]=max(dp[i],dp[j]+1);算法复杂度o(n^2);
2.每次以类似贪心的策略使序列的末尾项尽可能小,如此后面的数更容易添加,达到长度最大。
保证长度为i时,当前的末尾是已知最小的,某一项与末尾相等或者小时,则往前寻找到最适合的位置,更新相应位置的值(可能是末尾)。大于时长度加1,最终长度即为最长公共序列的长度。
在“使序列的末尾项尽可能小”时,使用了二分搜索,这是复杂度降低的关键,算法复杂度o(nlogn);
#include<bits/stdc++.h> using namespace std; int a1[100005]; int a2[100005]; int m[100005]; int a3[100005]; int main(){ int n;cin>>n; for(int i=0;i<n;i++){ scanf("%d",&a1[i]); m[a1[i]]=i; } for(int i=0;i<n;i++){ scanf("%d",&a2[i]); } int len=1;a3[1]=m[a2[0]]; for(int i=1;i<n;i++){ int l=0,r=len; if(m[a2[i]]>a3[len])a3[++len]=m[a2[i]]; else{ while(l<r){ int mid=(l+r)>>1; if(m[a2[i]]<a3[mid])r=mid; else l++; } a3[l]=min(a3[l],m[a2[i]]); } } cout<<len<<endl; return 0; }