洛谷 P1439 【模板】最长公共子序列【线性dp+dp模型转换】

news2025/1/25 4:46:17

原题链接:https://www.luogu.com.cn/problem/P1439

题目描述

给出 1,2,…,n 的两个排列 P1​ 和 P2​ ,求它们的最长公共子序列。

输入格式

第一行是一个数 n。

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

输出格式

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

输入输出样例

输入 #1

5 
3 2 1 4 5
1 2 3 4 5

输出 #1

3

说明/提示

  • 对于 50% 的数据, n≤1e3;
  • 对于 100% 的数据, n≤1e5。

解题思路:

首先一看题目,我去这不是经典dp模型最长公共子序列吗,这也太简单了,本来准备直接上最长公共子序列的模板秒了,但是一看数据范围,n=1e5,最长公共子序列模板题的时间复杂度为O(n^2),这里的n=1e5,时间复杂度就到达了1e10,这也太高了,这个时间复杂度肯定过不了,这个时候肯定是观察状态转移方程根据状态转移方程看能不能进行优化,一看状态转移方程好像找不到什么好的优化方式,这个优化方式不存在,我们再看是否能够挖掘什么性质进行优化,我们可以发现a,b数组都是一个1-n的一个排列,也就是说俩个数组中都是1-n中的每个数只出现一次,下面让我们来画一个图模拟一下题目给出的样例,看看是否具有什么性质。

(1):首先我们知道公共子序列是每个位置都对应相等的,例如上述图中描述的样例,如果我们选择3,那么第一个序列的3和第二个序列的3就都要选上,那么此时就无法选择1和2,因为如果还选择1,那么第一个序列中选出的就是[3,1],第二个序列中选出的就是[1,3],这样俩个序列都不相同的了,肯定是不行的,然后如果选择2第一个序列就是[3,2],第二个序列就是[2,3]了,这也肯定是不行的,但是我们选择1之后是可以选择4和5的,这个时候我们就可以发现一个明显的性质了,这个性质就是我们将俩个数组a和b数值相等的位置连线之后,我们选择的公共子序列的所有数值对的连线不能不能存在交叉的现象。

(2):那么我们怎么保证我们选择的所有数值对的连线不交叉呢,我们可以根据数组a各个元素的相对位置来进行对应映射对数组b进行重新赋值,例如上述图中样例,在数组a中3位于第一个位置,所以将b数组中的3重新赋值为1 ,数组a中2位置第二个位置,所以将b数组中的2重新赋值为2,其他的也是如下赋值即可,这样原来的数组b为[1,2,3,4,5],就转换为了[3,2,1,4,5],对于映射之后重新赋值的新数组b,选择了某个位置之后,就不能选择b之前比当前选择位置大的数,不能选择b之后比当前位置小的数,例如这个新b数组选择了1之后,就不能选择1之前的2,3,但是可以选择1之后的4,5,看到这个这不就是求最长上升子序列吗,这个时候我们就将题目原本的求最长公共子序列变为了求新的b数组最长上升子序列,这个题目n=1e5,不能采用最长上升子序列的朴素dp写法,因为最长上升子序列的朴素dp写法时间复杂度为O(n^2),这个复杂度过不了,应该采用最长上升子序列的二分+贪心的那个写法,这种写法时间复杂度为O(nlogn),这个时间复杂度是可以过的。

时间复杂度:将原本求最长公共子序列转换为求映射的新数组b的最长上升子序列,使用求最长上升子序列的二分+贪心写法时间复杂度为O(nlogn)

总结:这个题目属于诈骗题了,题目表面是求最长公共子序列,但是n非常大,n=1e5,显然最长公共子序列的那个O(n^2)解法过不了,观察状态转移方程也没有发现很明显的优化方式,但是我们画图之后发现了一个性质,就将原本的求最长公共子序列变为了求最长上升子序列,然后采用最长上升子序列二分+贪心写法这个题目就可以过了,这个题目纯属套着羊皮的狼,挂羊头卖狗肉,题目给的虽然是求最长公共子序列,但是本质上就是求最长上升子序列。

启发:

至于我为什么能发现这个性质是因为我做一个非常像的题,所以很快就发现了这个性质,很快就解决了这个题目,所以说还是需要学会知识的迁移吧,对于学到的东西多加总结融会贯通还是有好处的,这样对于学过的东西,以后遇到类似的题目还是有帮助的。

那个很像的题目的链接:https://www.acwing.com/problem/content/1014/

cpp代码如下

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>

using namespace std;

const int N = 1e5 + 10;

int n;
int a[N], b[N], f[N];
int q[N];
int main()
{
    cin >> n;
    unordered_map<int, int> mp;
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]), mp[a[i]] = i;
    for (int i = 1; i <= n; i++)
        scanf("%d", &b[i]), b[i] = mp[b[i]]; // 根据a数组对b数组重新赋值,映射出一个新的b数组

    // 对于新映射出的b数组求最长上升子序列,这里是最长上升子序列的二分+贪心的写法,时间复杂度O(nlogn)
    int len = 0;
    for (int i = 1; i <= n; i++)
    {
        int l = 0, r = len;
        while (l < r)
        {
            int mid = l + r + 1 >> 1;
            if (q[mid] < b[i])
                l = mid;
            else
                r = mid - 1;
        }
        len = max(len, r + 1);
        q[r + 1] = b[i];
    }
    // len记录的就是新b数组的最长上升子序列
    cout << len << endl;
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1383538.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Deepin使用记录-deepin安装docker

引用 本来想在deepin中直接安装mysql的开发环境的&#xff0c;但想到还是安装docker&#xff0c;然后在docker下安装比较方便&#xff0c;所以就有了本篇文章&#xff0c;先在deepin下安装docker。 经过本次安装&#xff0c;发现在deepin下安装docker是非常的简单&#xff0c…

自动执行 Active Directory 清理

Active Directory &#xff08;AD&#xff09; 可帮助 IT 管理员分层存储组织的资源&#xff0c;包括用户、组以及计算机和打印机等设备&#xff0c;这有助于管理员集中创建基于帐户和组的规则&#xff0c;并通过创建不合规的自动日志来强制执行和确保合规性。 不时清理AD是保…

ruoyi后台管理系统部署-3-安装redis

centos7安装redis 1. yum 安装 查看是否安装了redis yum installed list | grep redis ps -ef | grep redis安装epel 仓库&#xff08;仓库是软件包下载的&#xff0c;类似maven&#xff0c;nuget&#xff09; yum install epel-release搜索 redis 包 yum search redis安装…

YOLOv8 Ultralytics:使用Ultralytics框架进行SAM图像分割

YOLOv8 Ultralytics&#xff1a;使用Ultralytics框架进行SAM图像分割 前言相关介绍前提条件实验环境安装环境项目地址LinuxWindows 使用Ultralytics框架进行SAM图像分割参考文献 前言 由于本人水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评改正。更多精彩内容&#xf…

第 3 章 稀疏数组和队列

文章目录 3.1 稀疏 sparsearray 数组3.1.1 先看一个实际的需求3.1.2 基本介绍3.1.3 应用实例3.1.4 课后练习 3.2 队列3.2.1 队列的一个使用场景3.2.2 队列介绍3.2.3 数组模拟队列思路3.2.4 数组模拟环形队列 3.1 稀疏 sparsearray 数组 3.1.1 先看一个实际的需求  编写的五…

【EI会议征稿通知】第三届机器视觉、自动识别与检测国际学术会议(MVAID 2024)

第三届机器视觉、自动识别与检测国际学术会议(MVAID 2024) 2024 3rd International Conference on Machine Vision, Automatic Identification and Detection 第三届机器视觉、自动识别与检测国际学术会议(MVAID 2024)定于2024年4月26至28日在中国昆明隆重举行。MVAID 2024将…

关于git与git-lfs对文件压缩存储方面的研究

先说结论&#xff0c;git使用了Delta增量压缩算法&#xff0c;git-lfs实测没有进行任何压缩&#xff0c;这个结论让我很震惊。 测试过程如下&#xff1a; 测试git仓库自身的压缩 准备一个包含许多杂项文件的文件夹&#xff0c;大概几百M&#xff0c;要保证有一个txt文本文件…

openssl3.2 - 官方demo学习 - server-arg.c

文章目录 openssl3.2 - 官方demo学习 - server-arg.c概述笔记备注END openssl3.2 - 官方demo学习 - server-arg.c 概述 TLS服务器, 等客户端来连接; 如果客户端断开了, 通过释放bio来释放客户端socket, 然后继续通过bio读来aceept. 笔记 对于开源工程, 不可能有作者那么熟悉…

Kali Linux的下载安装以及基础配置

文章目录 前言一、Kali是什么&#xff1f;二、Kali的安装与下载Kali的下载Kali的安装 Kali的基本配置更新Kali源自定义Kali 前言 渗透测试&#xff08;Penetration Testing&#xff09;&#xff0c;简称为渗透测试或漏洞评估&#xff0c;是一种安全评估的方法&#xff0c;旨在…

MySQL单表的查询练习

作业要求&#xff1a; 作业实现&#xff1a; 首先&#xff0c;创建worker表并插入相关数据 CREATE TABLE worker (部门号 int(11) NOT NULL,职工号 int(11) NOT NULL,工作时间 date NOT NULL,工资 float(8,2) NOT NULL,政治面貌 varchar(10) NOT NULL DEFAULT 群众,姓名 varc…

js中关于字符串的创建和判断类型

文章目录 创建方法判断类型的技巧区分1、typeof2、instanceof 共点1、Object.prototype.toString.call2、库函数 参考链接&#xff1a;JS字符串的创建和常用方法 如何判断JS中一个变量是 string 类型 创建方法 字符串有着两种的创建方法&#xff0c;一个是使用构造函数&#x…

菜狗速递 快人一步

菜狗速递物流管理系统是一款针对网点管理人员开发的系统。 网点管理人员可以在该系统上进行员工信息的录入以及职能分配&#xff0c; 并能对客户的包裹进行一系列的处理&#xff0c;帮助客户查询订单信息&#xff0c;处理问题包裹等。 技术栈 基础框架&#xff1a;SpringBo…

springCloud使用apache的http类和RestTemplate以及Eureka

使用apache的&#xff1a; package com.csgholding.pvgpsp.eqp.util;import com.esotericsoftware.minlog.Log; import org.apache.commons.collections4.MapUtils; import org.apache.http.HttpEntity; import org.apache.http.client.config.RequestConfig; import org.apac…

腾讯云优惠券介绍、种类、领取入口及使用教程

腾讯云作为国内领先的云服务提供商&#xff0c;为广大的企业和开发者提供了优质的云计算、大数据、人工智能等服务。为了更好地吸引用户&#xff0c;腾讯云推出了多种优惠活动&#xff0c;其中就包括腾讯云优惠券。本文将详细介绍腾讯云的优惠券种类、领取入口以及使用教程。 一…

二分-补题

文章目录 造海船描述输入描述输出描述样例输入 1样例输出 1提示题解 寻找第一个1题目描述输入描述输出描述测试用例题解 查找数字是否出现描述输入描述输出描述样例输入 1样例输出 1题解 字典找数描述输入描述输出描述样例输入 1样例输出 1题解 寻找第一个偶数题目描述输入描述…

【AI的未来 - AI Agent系列】【MetaGPT】2. 实现自己的第一个Agent

在MetaGPT中定义的一个agent运行示例如下&#xff1a; 一个agent在启动后他会观察自己能获取到的信息&#xff0c;加入自己的记忆中下一步进行思考&#xff0c;决定下一步的行动&#xff0c;也就是从Action1&#xff0c;Action2&#xff0c;Action3中选择执行的Action决定行动…

怎么把workspace的数据导入到simulink进行FFT分析?

怎么把数据导入到simulink在这篇博客已经阐述了&#xff0c;那么如何把数据导入到simulink还能进行FFT分析呢&#xff1f; 首先我们看simulink的FFT分析界面&#xff0c;&#xff08;前置步骤&#xff1a;导入powergui模块&#xff0c;双击powergui模块&#xff0c;Tool选项卡…

第8章-第6节-Java中字符流的缓冲流

1、在说正题之前&#xff0c;先说一个小细节&#xff0c;不管是字节流还是字符流都要注意这个细节&#xff0c;具体看这篇博文&#xff1a;关于Java的IO流里面的方法read()的小细节 2、字符流的缓冲流&#xff1a; 1&#xff09;、BufferedWriter 方法名说明void newLine()写…

代码随想录刷题题Day32

刷题的第三十二天&#xff0c;希望自己能够不断坚持下去&#xff0c;迎来蜕变。&#x1f600;&#x1f600;&#x1f600; 刷题语言&#xff1a;C Day32 任务 ● 70. 爬楼梯 &#xff08;进阶&#xff09; ● 322. 零钱兑换 ● 279.完全平方数 1 爬楼梯&#xff08;进阶&#…

JavaScript的变量详解

一、变量的声明和赋值 编程中的程序其本质就是处理数据的过程&#xff0c;当输入指令时&#xff0c;就可以输出相应的内容&#xff0c;在输入和输出之间就是处理数据的过程。处理的数据可能有多种&#xff0c;多个&#xff0c;这时就需要使用不同的名字来存储、区分和提取不同的…