线性dp 总结详解

就是感觉之前 dp 的 blog 太乱了整理一下。

LIS(最长上升子序列)

例题

给定一个整数序列,找到它的所有严格递增子序列中最长的序列,输出其长度。

思路

拿到题目,大家第一时间想到的应该是\Theta (n^2)的暴力(dp)做法:

#include <bits/stdc++.h>
using namespace std;
int a[maxn],dp[maxn];
int main(){int n;cin>>n;for(int i=1;i<=n;i++){cin>>a[i];dp[i]=1;}for(int i=1;i<=n;i++){for(int j=1;j<i;j++){if(a[j]<a[i])dp[i]=max(dp[i],dp[j]+1);}}int ans=-1;for(int i=1;i<=n;i++) ans=max(ans,dp[i]);cout<<ans<<endl;return 0;
}

其中,dp_i表示以a_i为结尾的最长上升子序列的长度。而这,也就是 dp 的做法。当然,我们可以用用贪心+二分优化这个算法。这里就不详细展开说了,但是给出代码:

#include <bits/stdc++.h>
using namespace std;
int mn[maxn],a[maxn];
int binary_search(int a[],int r,int x){//二分查找,返回a数组中第一个>=x的位置int left=1;while(left<=right){int mid=(left+right)>>1;if(a[mid]<=x)left=mid+1;else right=mid-1;}return left;
}
int main(){int n;cin>>n;for(int i=1;i<=n;i++) {cin>>a[i];mn[i]=INF;//由于mn中存的是最小值,所以mn初始化为INF }mn[1]=a[1]; int ans=1;//初始时LIS长度为1 for(int i=2;i<=n;i++){if(a[i]>mn[ans])//若a[i]>=mn[ans],直接把a[i]接到后面 mn[++ans]=a[i];else//否则,找到mn中第一个>=a[i]的位置mn[j],用a[i]更新mn[j] mn[binary_search(mn,ans,a[i])]=a[i];}cout<<ans<<endl; return 0;
}

时间复杂度:\Theta(n\: log\: n)

LCS(最长公共子序列)

例题:P1439

思路

考虑暴力:设两个字符串的长度为n和m,对于两个字符串的每个字符,我们可以选,也可以不选。得到两个子序列后,比较是否相同要max(n,m),所以时间复杂度\Theta(2^{n+m}+max(n,m))

所以还是老老实实 dp 吧。

dp_{i,j}表示字符串 s 的第 i 位和字符串 t 的第 j 位的LCS长度。

那么有两种情况:

  • s_i=t_j:那么字符串 s 和字符串 t 的LCS长度就增加 1。
  • s_i\neq t_j:那么字符串 s 和字符串 t 的LCS长度无法继续增加,等于max(dp_{i-1,j},dp_{i,j-1})

Code

#include <bits/stdc++.h>
using namespace std;
int dp[maxn][maxm];//dp[i][j]表示s的第i位和t的第j位的LCS 
int main(){string s,t;cin>>s>>t;for(int i=0;i<=s.size();i++) {dp[0][i]=0;dp[i][0]=0;}//初始化 for(int i=1;i<=s.size();i++){for(int j=1;j<=t.size();j++){if(s[i-1]==t[j-1])dp[i][j]=dp[i-1][j-1]+1;//相等就加1 elsedp[i][j]=max(dp[i-1][j],dp[i][j-1]);}//不相等就比较 }cout<<dp[s.size()][t.size()]<<endl;return 0;
}

LCIS(最长公共上升子序列)

例题:CF10D

思路

看到题目,第一反应就是先求 LCS,再求 LIS。

对于(a_i,b_j)状态时 ,由于 dp 状态就决定了,b_j是一定作为这个状态下 LCIS 的结尾的,所以对于a_i,就有两种情况,将其纳入LCIS或者不纳入。

  • a_i\neq b_j -> dp_{i,j}=dp_{i-1,j}
  • a_i=b_j -> dp_{i,j}=dp_{i-1,j-1}

然后用滚动数组优化一下就OK力。

Code

#include <bits/stdc++.h>
using namespace std;
int dp[maxn],a[maxn],b[maxn];
int main(){int n;cin>>n;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++)cin>>b[i];int ans=0;for(int i=1;i<=n;i++){int tmp=0;for(int j=1;j<=n;j++){if(a[i]==b[j])dp[j]=max(dp[j],tmp+1);if(a[i]>b[j])tmp=max(tmp,dp[j]);        ans=max(dp[j],ans);}}cout<<ans<<endl;return 0;
}

字符串编辑距离

例题:P2758

思路

首先,如果 1 个字符串的长度为 0,那答案就是另一个字符串的长度。所以,我们令dp_{i,j}表示

a_{1...i}转换为b_{1...j}所需的最少操作次数。

也就是说:dp_{0,j}=jdp_{i,0}=i

接下来,继续思考,发现如果a_i=b_j,那么相同,无需变化dp_{i,j}=dp_{i-1,j-1}

如果不相同,dp_{i,j}=min(dp_{i-1,j-1},min(dp_{i-1,j},dp_{i,j-1}))+1

Code

#include <bits/stdc++.h>
using namespace std;
char a[maxn],b[maxn];
int dp[maxn][maxn];
int main(){int n;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<=strlen(a);i++)dp[i][0]=i;for(int j=1;j<=strlen(b);j++)dp[0][j]=j;for(int i=1;i<=strlen(a);i++){for(int j=1;j<=strlen(b);j++){if(a[i-1]==b[j-1])//相同时距离不变dp[i][j]=dp[i-1][j-1];else//不同时取三个位置的最小值再+1dp[i][j]=min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1;}}cout<<dp[strlen(a)][strlen(b)]<<endl;return 0;
}

最大子序列和

例题

对于给定序列,寻找它的连续的最大和子数组。

思路

非常简单,你只需要比较一下a_idp_{i-1}+a_i的大小就可以了。

Code

#include <bits/stdc++.h>
using namespace std;
int a[maxn],dp[maxn];
int main(){int n;cin>>n;for(int i=1;i<=n;i++)cin>>a[i];int ans=-inf;for(int i=2;i<=n;i++){dp[i]=max(dp[i-1]+a[i],a[i]);ans=max(ans,dp[i]);}cout<<ans<<endl;return 0;
}

数字三角形

例题

给出一个数字三角形,现在要从左上角走到第 i 行第 j 列,每一步只能走到相邻的结点,求经过的结点的最大数字和。

思路

非常简单,易得状态转移方程:dp_{i,j}=a_{i,j}+max(dp_{i-1,j},dp_{i-1,j-1})

Code

#include<bits/stdc++.h>
using namespace std;
int a[maxn][maxn],dp[maxn][maxn];
int main(){int n;cin>>n;for(int i=1;i<=n;i++){for(int j=1;j<=i;j++){cin>>a[i][j];dp[i][j]=a[i][j];}}for(int i=n-1;i>=1;i--){for(int j=1;j<=i;j++)dp[i][j]+=max(dp[i+1][j],dp[i+1][j+1]);}cout<<dp[1][1]<<endl;return 0;
}

最大子矩阵和

例题

给定一个n行m列的整数矩阵,现在要求一个子矩阵,使其各元素之和为最大。输出这个和。

思路

首先,我们知道这个矩阵最后肯定在第i行和第j行之间。所以,我们用一个数组记录这第 i 行到第 j 行的每一列的和(这句话可能有点绕,可以多读几遍) 。然后,第 i 行到第 j 行的最大子矩阵和就是这个数组的最大子段和。

Code

#include <bits/stdc++.h>
using namespace std;
int a[maxn][maxn];
int sum[maxn];//表示i-j行对应列元素的和
int main(){int n;cin>>n;for(int i=0;i<n;i++){for(int j=0;j<n;j++)cin>>a[i][j];}int ans=-INF;for(int i=0;i<n;i++){memset(sum,0,sizeof(sum));for(int j=i;j<n;j++){//下面是针对数组sum求最大子段和的动态规划算法int tmp=0;for(int k=0;k<n;k++){sum[k]+=a[j][k];tmp+=sum[k];if(tmp<0)tmp=sum[k];ans=max(tmp,ans);}}}cout<<ans<<endl;return 0;
}

结尾

这篇 blog 是 up 在 2024CSP-J 初赛前一天晚上赶出来的,主要还是因为 2023CSP-J 初赛考了太多线性 dp(虽然今年大概率不考了)。祝大家 2024CSP-J RP++!!!

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

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

相关文章

锐尔15注册机 锐尔文档扫描影像处理系统15功能介绍

锐尔文档扫描影像处理系统是一款全中文操作界面的文件、档案扫描及影像优化处理软件&#xff0c;是目前国内档案数字化行业里专业且优秀的影像优化处理软件。 无论是从纸质文件制作高质量的影像文件&#xff0c;或是检查已经制作好的影像文件&#xff0c;锐尔文档扫描影像处理…

LangChain 和 Elasticsearch 加速构建 AI 检索代理

作者&#xff1a;来自 Elastic Joe McElroy, Aditya Tripathi, Serena Chou Elastic 和 LangChain 很高兴地宣布发布新的 LangGraph 检索代理模板&#xff0c;旨在简化需要代理使用 Elasticsearch 进行代理检索的生成式人工智能 (GenAI) 代理应用程序的开发。此模板预先配置为使…

C++第十一节课 new和delete

一、new和delete操作自定义类型 new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构造函数和析构函数&#xff08;new会自动调用构造函数&#xff1b;delete会调用析构函数&#xff09; class A { public:A(int a 0): _a(a){cout <&l…

使用express或koa或nginx部署history路由模式的单页面应用

使用hash模式会有#&#xff0c;影响美观&#xff0c;所以使用history模式会是个更好的选择。 前端项目打包上线部署&#xff0c;可以使用下面的方式部署history模式的项目&#xff0c;下面以 jyH5 为例 expressjs部署 express脚手架搭建的app.js中添加如下代码&#xff1a; …

Superset二次开发之优化Mixed Chart 混合图(柱状图+折线)

背景 基于Mixed Chart(柱状图+折线)作图,显示 某维度A Top10 + 其他 数据,接口返回了值为 undefined 的某维度A 数据,前端渲染成 某维度A 值为 0 此图表存在的问题: 图表控件编辑页面,即便数据集正常查询出 Top10 + ‘其他’ 数据,但是堆积图表渲染时,返回了 值为 0…

【网络通信基础与实践第四讲】用户数据报协议UDP和传输控制协议TCP

一、UDP的主要特点 1、UDP是无连接的&#xff0c;减少了开销和发送数据之前的时延 2、UDP使用尽最大努力交付&#xff0c;但是不保证可靠交付 3、UDP是面向报文的。从应用层到运输层再到IP层都只是添加一个相应的首部即可 4、UDP没有拥塞机制&#xff0c;源主机以恒定的速率…

Zookeeper安装使用教程

# 安装 官网下载安装包 #配置文件 端口默认8080&#xff0c;可能需要更改一下 #启动 cd /Users/lisongsong/software/apache-zookeeper-3.7.2-bin/bin ./zkServer.sh start #查看运行状态 ./zkServer.sh status #停止 ./zkServer.sh stop #启动客户端 ./zkCli.sh ls /

Linux ubuntu debian系统安装UFW防火墙图形化工具GUFW

GUFW是UFW的图形化前端&#xff0c;可以通过以下命令安装&#xff1a; sudo apt install gufw安装成功后&#xff0c;可以通过应用程序菜单启动GUFW&#xff0c;在图形界面中&#xff0c;可以方便地添加、修改和删除规则&#xff0c;查看状态和日志。

java之杨辉三角问题

给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 如何实现呢&#xff1f; 思路&#xff1a;首先&#xff0c;我们可以将杨辉三角视作i行j列的二维数组。除了第一行和第二行之外&am…

IPD流程体系:IPD在硬件产品开发中的应用

目录 1、内容简介 2、开发各阶段介绍 3、PVT阶段 4、资源群更新 作者简介 1、内容简介 在硬件类相关产品的开发过程中&#xff0c; 每个阶段的工作都是需要按照一定的流程、规范和标准去进行的。 整体还是相对瀑布化的流程&#xff0c; 每个阶段的输入、输出、准入、准…

C++初阶学习——探索STL奥秘——反向迭代器

适配器模式是 STL 中的重要组成部分&#xff0c;除了容器适配器外&#xff0c;还有 选代器适配器&#xff0c;借助 选代器适配器 &#xff0c;可以轻松将各种容器中的普通迭代器转变为反向迭代器&#xff0c;这正是适配器的核心思想 注:库中的反向迭代器在设计时&#xff0c;为…

【HTTP】请求“报头”(Host、Content-Length/Content-Type、User-Agent(简称 UA))

Host 表示服务器主机的地址和端口号 URL 里面不是已经有 Host 了吗&#xff0c;为什么还要写一次&#xff1f; 这里的 Host 和 URL 中的 IP 地址、端口什么的&#xff0c;绝大部分情况下是一样的&#xff0c;少数情况下可能不同当前我们经过某个代理进行转发。过程中&#xf…

С++第十三节课 string初体验

一、string类的相关函数 string实际上也就是一个管理字符的顺序表&#xff01; 如果我们需要遍历一个字符串&#xff0c;怎么实现&#xff1f; 我们可以通过下标访问操作符 size实现字符串的遍历&#xff01; int main() {string s1("hello world");// 遍历一个字…

不可思议的效率飞跃:RPA如何重塑你的工作流程,释放人力潜能!

RPA简介 机器人流程自动化&#xff08;Robotic Process Automation&#xff0c;简称RPA&#xff09;是一种模拟人类用户操作的软件技术&#xff0c;它通过自动化执行重复性、规律性强的任务来提高工作效率和准确性。RPA软件机器人可以模拟鼠标点击、键盘输入、数据复制粘贴等操…

anaconda的windows新手安装及配置教程(适用于物联网工程、计算机专业)

第一步:点击免费下载 点击我直达anaconda官网">——>点击我直达anaconda官网 第二步:跳过注册 第三步:下载windows版本 第四步:安装步骤 1.Next (下一步) 2.I Agree (我同意) 3.默认即可,下一步 4.安装地址可以选到D盘,如果没有默认也行,只是一个…

OpenAI GPT o1技术报告阅读(4)- 填字游戏推理

✨继续阅读报告&#xff1a;使用大模型来学习推理(Reason) 原文链接&#xff1a;https://openai.com/index/learning-to-reason-with-llms/ 这次我们继续看一个填字游戏的案例。 我们先看下问题&#xff1a; 解决以下填字游戏&#xff1a; Across&#xff08;横向&#xff09…

推荐2024年好用的4款日语翻译工具

日语在学习研究&#xff0c;商务合作&#xff0c;旅游文化交流等多个领域还是占有着一个比较重要的作用&#xff0c;将中日两种语言进行准确地翻译能够这些活动更加高效有益地进行和发展。因此好的翻译工具便尤为重要&#xff0c;今天我也给大家挑选了几款优秀地日语翻译工具。…

可视化工具箱-Visualization Toolkit(VTK)

一、Visualization Toolkit&#xff08;VTK&#xff09;简概 可视化工具箱&#xff08;VTK&#xff09;&#xff0c;是一个用于3D计算机图形、图像处理和科学可视化的开源软件系统&#xff0c;其包含C类库和Tcl/Tk、Java与python的解释型接口层。VTK支持各种可视化算法&#xf…

电机设计及电机仿真APP系列之—轴向磁通电机仿真APP

电机的各种工作状态和参数变化。用户可通过调整仿真参数&#xff0c;快速得到电机的响应和性能参数&#xff0c;从而进行针对性的优化和改进。借助仿真APP&#xff0c;可大大减少电机设计迭代次数和成本&#xff0c;提高测试效率和准确性。 小编整理了10款不同类型的电机仿真A…

前端vue-v-for循环遍历

&#xff08;item,index&#xff09;in list中&#xff0c;index这个索引可加可不加&#xff0c;item代表list中的每一个元素&#xff0c;list可以是数组&#xff0c;也可以是对象&#xff0c;要遍历谁就把 &#xff08;item,index&#xff09;in list加在哪里。 关于加不加&a…