P1439 两个排列的最长公共子序列-普及+/提高

P1439 两个排列的最长公共子序列

题目描述

给出 1,2,…,n1,2,\ldots,n1,2,,n 的两个排列 P1P_1P1P2P_2P2 ,求它们的最长公共子序列。

输入格式

第一行是一个数 nnn

接下来两行,每行为 nnn 个数,为自然数 1,2,…,n1,2,\ldots,n1,2,,n 的一个排列。

输出格式

一个数,即最长公共子序列的长度。

输入输出样例 #1

输入 #1

5 
3 2 1 4 5
1 2 3 4 5

输出 #1

3

说明/提示

  • 对于 50%50\%50% 的数据, n≤103n \le 10^3n103
  • 对于 100%100\%100% 的数据, n≤105n \le 10^5n105

solution

动态规划

  • 设两个序列为 a,b 如果定义 f[i] 为 a, b 中 b[i]为结尾的公共子序列的最大长度,则 f[i]为 a 中在b[i]之前那些数j的最大的f[j] + 1

  • 1 定义公式

    •  f[i] 以 b[i] 为结尾的最长公共子序列长度
      
  • 2 递推关系

    •  f[i] = f[j] + 1
      
    •  f[j] 为 a 中,b[i] 左侧的最大的f[k] k = 1...i-1
      
  • 3 结果

    •  ans = max(f[i])
      
  • 4 可以借助树状数组在 log n 时间内求出 max(f[k])
    其实如果以 b[i] 在, a中的位置作为x[i]的话,最长公共子序列其实x[i]就是最大递增子序列,同样可以用dp求出

代码

#include "cstdio"
#include "iostream"
#include "vector"
#include "cstring"
#include "queue"
#include "algorithm"
#include "unordered_map"
#include "cmath"

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-folding-constant"
using namespace std;

/*
 * 题目大意:1-n 的两个排列,求最长公共子序列
 * 数据范围: n <= 10^5
 *
 * 思路:动态规划
 * 设两个序列为 a,b 如果定义 f[i] 为 a, b 中 b[i]为结尾的公共子序列的最大长度,则 f[i]为 a 中在b[i]之前那些数j的最大的f[j] + 1
 * 
 * 1 定义公式
 *      f[i] 以 b[i] 为结尾的最长公共子序列长度
 * 2 递推关系
 *      f[i] = f[j] + 1
 *      f[j] 为 a 中,b[i] 左侧的最大的f[k] k = 1...i-1
 * 3 结果
 *      ans = max(f[i])
 *
 * 4 可以借助树状数组在 log n 时间内求出 max(f[k])
 * 
 * 其实如果以 b[i] 在, a中的位置作为x[i]的话,最长公共子序列其实x[i]就是最大递增子序列,同样可以用dp求出
 *     
 */

const int N = 1e5 + 5;
int n, a[N], b[N], c[N], pos[N];

int low_bit(int x) {
    return x & -x;
}

void add(int x, int v) {
    while (x <= n) {
        c[x] = max(c[x], v);
        x += low_bit(x);
    }
}

int sum(int x) {
    int ans = 0;
    while (x > 0) {
        ans = max(ans, c[x]);
        x -= low_bit(x);
    }
    return ans;
}


int main() {
    scanf("%d", &n);

    for (int i = 1; i <= n; i++) scanf("%d", a + i), pos[a[i]] = i;
    for (int i = 1; i <= n; i++) scanf("%d", b + i);

    int ans = 0;
    for (int i = 1; i <= n; i++) {
        int x = sum(pos[b[i]] - 1);
        add(pos[b[i]], x + 1);
        ans = max(ans, x + 1);
    }


    printf("%d\n", ans);
    return 0;
}


#pragma clang diagnostic pop

结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智趣代码实验室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值