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;
}

 

posted @ 2020-08-20 00:00  mohari  阅读(147)  评论(0编辑  收藏  举报