P1439 【模板】最长公共子序列(LCS)

先来看一看普通的最长公共子序列

给定字符串A和B,求他们的最长公共子序列

DP做法:

设f[i][j]表示A[1~i]和B[1~j]的最长公共子序列的长度

那么f[i][j]=max(f[i-1][j],f[i][j-1])

在上面的基础上,如果A[i]=B[j],则f[i][j]=max(f[i][j],f[i-1][j-1]+1)

代码:

 for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      {
        dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
        if(a1[i]==a2[j])
        dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
      }

复杂度为O(mn)


那么这道题由于1e5的数据,不论是时间还是空间都会爆炸,就需要考虑另一种做法

我们来观察这个题的特征,发现A和B都是1~n的全排列,也就是说A和B中元素是一样的,考虑充分利用这个特征。

 

——by pks大佬

代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

int n,len;
int atlas[100005],a[100005],f[100005];

int main()
{
    n=read();
    for(int i=1,x;i<=n;i++) 
    {
        x=read();
        atlas[x]=i;//每个数在序列1出现的位置 
    }
    for(int i=1,x,now;i<=n;i++) 
    {
        x=read();
        now=atlas[x];//在a序列找出x的位置 
        if(now>f[len])//如果位置在上一个的后面 
        {
            f[++len]=now;
        }
        else
        {
            int j=lower_bound(f+1,f+1+len,now)-f;//在f中找到第一个大于等于now的位置 
            f[j]=now;//更新 
        }
    }
    cout<<len;
 } 
原文地址:https://www.cnblogs.com/lcezych/p/11126816.html