【训练题12:LCS转LIS】最长公共子序列 | 洛谷 P1439

最长公共子序列 | 洛谷 P1439

难度

普 及 + / 提 高 \color{green}普及+/提高 +/
洛谷模板题

题意

给两个 N N N 的全排列 P A P_A PA P B P_B PB
求两个全排列的 最长公共子序列(Longest Common Subsequence) 的长度。

数据范围

N ≤ 1 0 5 N\le 10^5 N105

思路

  • 若普通的动态规划这么一做,明显是 O ( N 2 ) O(N^2) O(N2) 的,时间空间都炸掉。
  • 我们需要使用: L C S LCS LCS L I S LIS LIS大法!
  • 在这里插入图片描述
  • P A P_A PA P B P_B PB 进行映射后,对每个位置的元素的对应下标进行倒序记录(见上绿色部分)。若找不到则为空集。
  • 把所有记录储存成一个数组 S S S ,则数组 S S S 为:[4,2,5,3,1,4,2]
  • 接下来,我们 S S S进行LIS所得到的结果即为原LCS的答案。(证明易得略)。
  • L I S LIS LIS的时间复杂度为严格 O ( N log ⁡ N ) O(N\log N) O(NlogN)
  • 但是在某些极端情况(比如两个原数组都是充满一个字母‘A’),会退化到 O ( N 2 log ⁡ N ) O(N^2\log N) O(N2logN)
  • 但是这题的所有元素位置的映射只有一个,因此不会产生这种退化。

核心代码

时间复杂度 O ( N log ⁡ N ) O(N\log N) O(NlogN)

/*
 _            __   __          _          _
| |           \ \ / /         | |        (_)
| |__  _   _   \ V /__ _ _ __ | |     ___ _
| '_ \| | | |   \ // _` | '_ \| |    / _ \ |
| |_) | |_| |   | | (_| | | | | |___|  __/ |
|_.__/ \__, |   \_/\__,_|_| |_\_____/\___|_|
        __/ |
       |___/
*/
const int MAX = 1e5+50;
const int INF = 0x3f3f3f3f;

int pos[MAX];
int aa[MAX];
int dp[MAX];
int main()
{
    
    
    int n;scanf("%d",&n);
    for(int i = 1;i <= n;++i){
    
    
        int t;scanf("%d",&t);
        pos[t] = i;
    }
    fill(dp,dp+MAX,INF);
    for(int i = 1;i <= n;++i){
    
    
        int t;scanf("%d",&t);
        aa[i] = pos[t];
        int p = lower_bound(dp,dp+MAX,aa[i]) - dp;
        dp[p] = aa[i];
    }
    int ans = 0;
    for(int j = 0;j < MAX;++j){
    
    
        if(dp[j] == INF){
    
    
            cout << j;
            break;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45775438/article/details/109696901