首页 > 其他分享 >最长公共子序列

最长公共子序列

时间:2024-11-03 12:59:11浏览次数:5  
标签:P1 int maxn 公共 序列 最长 dp

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

DP的经典例题,适合学完导弹拦截后再来学习

O(\(N^2\))

按照DP常规思考方法

我们令dp[i][j]为P1序列前i个子序列和P2序列前j个子序列的最长公共子序列长度

  • 注意,这是一种常见的设dp状态的方式,可以积累)

所以我们进而思考状态转移方程

对于\(dp[i][j]\) 应该和\(dp[i-1][j],dp[i][j-1],dp[i-1][j-1]\)有关

  • 无论\(p1[i]\)是否等于\(p2[j],dp[i][j]=dp[i-1][j]\),同理,\(dp[i][j]=dp[i][j-1]\)
    所以\(dp[i][j]=max(dp[i-1][j],dp[i][j-1])\)
  • 而如果\(p1[i]==p2[j]\) 那么最前面的公共子序列长度即可以+1,所以\(dp[i][j]=dp[i-1][j-1]+1\)
  • 而当我们状态转移,状态从(i-1,j),(i-1,j-1),(i,j-1)这个三个转移过来,这个又从(i-2,j),(i-2,j-2),(i-1,j-2),(i-2,j-1),(i-2,j-2),(i-1,j-1),(i-1,j-2),(i,j-2)转移,以此类推,所以在状态转移到(i,j)之前,从(1,1)到(i-1,j)都有值,所以才有代码中的循环

综上
$dp[i][j]=max(dp[i-1][j],dp[i][j-1]) $

\(if(p1[i]==p2[j]) dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1)\)

#include<iostream>

using namespace std;
const int maxn=1e4+10;
int n;
int a[maxn],b[maxn];
int f[maxn][maxn];
int main(){
	cin>>n;
	for(int i=1;i<=n;++i) cin>>a[i];
	for(int i=1;i<=n;++i) cin>>b[i];
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j){//状态转移前都有值
			f[i][j]=max(f[i-1][j],f[i][j-1]);
			if(a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1); 
		} 
	cout<<f[n][n];
	return 0;
} 

O(\(nlogn\))

在第一种的处理方法中,我们忽略了题目条件中的一个性质:全排列

而此题与导弹拦截有类似之处,我们思考是否有可能将此题转化为最长不下降子序列

在最长不下降子序列中,从一个序列中找一个最长不下降子序列
而此题中是找两个最长公共子序列,所以我们找出的子序列即为另一个序列子序列,那就能解决该问题

(核心思路)

如果我们保证P1序列是上升序列,而从P2序列找到一个最长不下降子序列一定是P1序列的子序列,那么该序列长度即为所求

重新编号就能保证P1序列是上升序列

  • 举例
    P1:3 2 1 4 5
    P2:1 2 3 4 5
    重新编号(全排列保证了这样重新编号的合理性)
    P1: 1 2 3 4 5
    P2: 3 2 1 4 5
  1. 重新编号也很简单,有map映射即可
  2. 求最长上升子序列用导弹拦截的方法即可

CODE

#include<bits/stdc++.h>
using namespace std;
map<int,int>m;
int n;
const int maxn=1e5+10;
int a[maxn];
int f[maxn];
int main(){
	cin>>n;
	for(int i=1;i<=n;++i){
		int x;
		cin>>x;
		m[x]=i;
	}
	int t=0;
	for(int i=1;i<=n;++i){
		int x,l=0,r=t;
		cin>>x;
		x=m[x];
		while(l<=r){
			int mid=(l+r)>>1;
			if(x<f[mid]) r=mid-1;
			else l=mid+1;
		}
		if(l>t) t=l;
		f[l]=x; 
	}
	cout<<t<<endl;
	return 0; 
}

标签:P1,int,maxn,公共,序列,最长,dp
From: https://www.cnblogs.com/guiyou/p/18523160

相关文章

  • LeetCode 3165.不包含相邻元素的子序列的最大和:单点修改的线段树(动态规划)
    【LetMeFly】3165.不包含相邻元素的子序列的最大和:单点修改的线段树(动态规划)力扣题目链接:https://leetcode.cn/problems/maximum-sum-of-subsequence-with-non-adjacent-elements/给你一个整数数组nums和一个二维数组queries,其中queries[i]=[posi,xi]。对于每个查......
  • 计算机毕设设计项目 nodejs基于微信平台的学校公共场所及资源预约系统的设计与实现
    标题:nodejs基于微信平台的学校公共场所及资源预约系统的设计与实现基于Node.js和微信平台的学校公共场所及资源预约系统可以为师生提供一个便捷、高效的在线预约平台。以下是一些主要的功能模块这些功能旨在提升用户体验并简化预约流程:1.用户管理•注册与登录:支持用户通过......
  • 序列化与反序列化+SQL函数
    序列化其实就是一种对象,平时写的自定义类,内存上就是对象,可以保存到硬盘上,就是序列化,反过来就是反序列化序列化:对象转换为字节反序列化:字节重构为对象实际上也是输入输出流,只不过加了Object即ObjectOutputStreamObjectOutputStream类构造方法:OutputStream里面传的是FileO......
  • 时间序列算法---ARIMA
      现代时间序列分析方法主要有两个不同的方向:一个方向是由外向内的分析视角产生的方法是与确定性因素分解相关的方法;一个方向是由内向外的分析视角产生的方法是时域分析方法。一、确定性因素分析方法  因素分解方法认为所有的序列波动都可以归纳为受到如下四大类因素......
  • Lca最近公共祖先(非常实用)
    一般求lca的方式就是基于下面的模板,中间的过程就不推理了,有兴趣可以去听听y总的课,讲的很详细模板题给定一棵包含 n 个节点的有根无向树,节点编号互不相同,但不一定是 1∼n。有 m 个询问,每个询问给出了一对节点的编号 x 和 y,询问 x 与 y 的祖孙关系。输入格式输......
  • 《上海市计算机学会竞赛平台2024年8月月赛丙组题目T1 统计得分 T2 等差数列的素性 T3
    T1统计得分内存限制: 256 Mb时间限制: 1000 ms题目描述在一场知识竞赛中,选手答对一题得 11 分,答错不得分且要倒扣 11 分,但扣分不能让分数小于 00。给定一个由 Y 及 N 构成的字符序列,答对记为 Y,答错记为 N。选手一开始从 00 分开始,请输出选手最后的得分......
  • 【Matlab算法】基于MATLAB实现时间序列预测(附MATLAB完整代码)
    基于MATLAB实现时间序列预测前言正文代码实现结果图结果说明总结前言时间序列预测是许多实际应用中的重要任务,涉及领域包括经济、金融、气象等。其中,自回归集成移动平均(ARIMA)模型是一种广泛使用的时间序列预测方法,因其简单有效而备受青睐。在本文中,......
  • 为什么实现Serializable接口就可以序列化
    在Java中,对象序列化是将对象的状态转换为字节流的过程,以便将其写入磁盘,或通过网络将其发送到另一个运行Java的虚拟机。如果一个类实现了Serializable接口,那么它的对象就可以被序列化。实现Serializable接口允许类的实例在进行输入/输出操作时,可以以平台独立的方式转化为字节流。......
  • 序列型动态规划
    1、小蜘蛛题目描述zty一共养了n只小蜘蛛,第i只小蜘蛛有一个编号Ai,这n只小蜘蛛的编号恰好构成了一个长度为n的排列。小蜘蛛们在交友时总喜欢站成一排。他们的交友方式也很特别,每只小蜘蛛只会主动和在自己左方,且离自己最近的编号比自己小的小蜘蛛成为好朋友。若不存在,则不......
  • 斐波那契时间序列,精准捕捉市场拐点 MT4免费公式源码!
    指标名称:斐波那契时间序列版本:MT4ver.2.01斐波那契时间序列是一种技术分析工具,通过将斐波那契数列(如1,2,3,5,8,13等)应用于时间轴上,用于预测市场价格的时间周期拐点。斐波那契时间序列在股票、外汇和其他市场分析中常用,帮助预测趋势反转或调整发生的时间节点。斐波那......