DP基础相关笔记

news2024/12/24 0:34:10

基础 DP

LIS

LIS(Longest Increasing Subsequence),顾名思义,就是最长上升子序列问题。

在这里我们要区分一下子串和子序列的区别,很简单,子串连续,子序列可以不连续。然而就在几小时之前本蒟蒻还不知道

简单来说,就是给出一个内容不重复的序列,求它的最长上升子序列。听君一席话,如听一席话

下面介绍两种做法, O ( n 2 ) O(n^2) O(n2) 的 DP 做法和 O ( n log ⁡ n ) O(n\log n) O(nlogn) 的二分做法。

O ( n 2 ) O(n^2) O(n2) DP

我们用 dp[i] 表示以 a[i] 为结尾的 LIS,剩下的自己理解就好啦 QwQ 学了优化之后就不会朴素做法了

#include <bits/stdc++.h>
using namespace std;

const int maxn=105,inf=0x7f7f7f7f;
int a[maxn],dp[maxn],n,ans=-inf;

int main()
{
    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);
    for(int i=1;i<=n;i++) 
        ans=max(ans,dp[i]);
    cout<<ans;
    return 0;
}
O ( n log ⁡ n ) O(n\log n) O(nlogn) 二分

显然,对于一个 LIS,要让它结尾的数尽量的小,才能使LIS最长。

举个栗子:对于“ 5201314 \texttt{5201314} 5201314”,第一步为“ 5 \texttt{5} 5”;第二步发现 2 < 5 2<5 2<5,所以换为“ 2 \texttt{2} 2”;第三步发现 0 < 2 0<2 0<2,所以换为“ 0 \texttt{0} 0”;第四步发现 1 > 0 1>0 1>0,把 1 1 1放进去变为“ 05 \texttt{05} 05”;第五步发现 0 < 3 < 5 0<3<5 0<3<5,所以换为“ 03 \texttt{03} 03”,以此类推。

对于这个的实现,我们可以巧妙地运用 lower_bound 函数进行二分查找,查找这个要放进去的值所在的区间。

代码如下:

#include <bits/stdc++.h>
using namespace std;

int a[105],f[105];//f is LIS

int main()
{
    int n;cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    f[1]=a[1];
    int len=1;
    for(int i=2;i<=n;i++)
    {
        if(a[i]>f[len]) len++,f[len]=a[i];
        else
        {
            int j=lower_bound(f+1,f+n+1,a[i])-f;
            f[j]=a[i];
        }
    }
    cout<<len;
    return 0;
}

发现自己真的是鱼,差点没写出来

LCS

LCS(Longest Common Sequence),顾名思义,就是最长公共子序列问题。

同样的,还是有两种不同时间复杂度的做法,一种 O ( n 2 ) O(n^2) O(n2),一种 O ( n log ⁡ n ) O(n\log n) O(nlogn)

O ( n 2 ) O(n^2) O(n2) DP

假设 dp ⁡ ( i , j ) \operatorname{dp}(i,j) dp(i,j) 为序列 A = a 1 a 2 ⋯ a i A=a_1a_2\cdots a_i A=a1a2ai 与序列 B = b 1 b 2 ⋯ B j B=b_1b_2\cdots B_j B=b1b2Bj 的最长公共子序列的长度。当 i = 0 i=0 i=0 j = 0 j=0 j=0 时,空序列是 A A A B B B 序列的最长子序列,状态转移方程如下:
d p ( i , j ) = { 0 i = 0 ∨ j = 0 d p ( i − 1 , j − 1 ) + 1 i , j > 0 , x i = y j max ⁡ ( d p ( i , j − 1 ) , d p ( i − 1 , j ) ) x i ≠ y j dp(i,j)= \begin{cases}0&i=0\vee j=0\\\\ dp(i-1,j-1)+1&i,j>0,x_i=y_j\\\\ \max(dp(i,j-1),dp(i-1,j))&x_i\neq y_j \end{cases} dp(i,j)= 0dp(i1,j1)+1max(dp(i,j1),dp(i1,j))i=0j=0i,j>0,xi=yjxi=yj

O ( n log ⁡ n ) O(n\log n) O(nlogn) 二分

我们可以建立一个映射,把序列 A A A 中的每一个元素映射为它对应的数组下标(这里本可以用 map 炫技,但是我们还是采用朴素的数组实现),显然这个序列是上升的,我们把 B B B 中可以转换的元素都转换为它在 A A A 中的数组下标,由于要满足递增才能保证序列公共,所以我们就把问题转化成了一个 LIS 问题。

代码如下:

#include <bits/stdc++.h>
using namespace std;
int a[100005],b[100005],c[100005],dp[100005],mp[100005];
int main()
{
    int n;cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i],mp[a[i]]=i;
    for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    for(int i=1;i<=n;i++)
        c[i]=mp[b[i]];//c存储公共子序列
    int temp=0,ans=-0x7fffffff;
    for(int i=1;i <= n;i++)
	{
        int j=upper_bound(dp+1,dp+temp+1,c[i])-dp;
        if(j==temp+1) temp++,dp[j]=c[i];
        else dp[j]=c[i];
    }
    cout<<temp;
    return 0;
}

状压 DP

状压 DP 的特点:

  • 数据规模的某一维或几维很小
  • 最优性原理
  • 无后效性

状压 DP 的灵魂就是位运算和二进制,可以复习一下 qwq。

详见 P1896题解。

状压 DP 位运算技巧,转载自 Xu brezza,原文链接

  1. 询问第 i i i 位是否为 1 1 1:

    x&(1<<(i-1))
    
    • 如果这么写返回的不是 1 1 1
    (x>>(i-1))&1
    
    • 这样才返回 01 01 01
  2. x x x i i i 位取反

    x^=1<<(i-1)
    
  3. x x x i i i 位变为 1 1 1

    x|=1<<(i-1)
    
  4. x x x i i i 位变为 0 0 0

    x&=(~(1<<(i-1)))
    
  5. 去掉 x x x 最右边的 1 1 1,也就是 lowbit ( x ) \text{lowbit}(x) lowbit(x)

    x&=x-1
    
  6. 取出最右边的 1 1 1 ,还是 lowbit ( x ) \text{lowbit}(x) lowbit(x)

    x&(-x)
    
  7. 判断是否有连续的 1 1 1

    x&(x<<1)
    

还是注意,不返回 1 1 1

  1. 枚举子集

敲黑板,非常重要且实用!

for(int y=x;y;y=(y-1)&x)

数位 DP

数位 DP,顾名思义,就是针对数位的 DP。

举个栗子,求给定区间中,满足给定条件的,某个进制数或此类数的数量。给定条件通常与数位有关,例如数位之和、指定数码个数、数的大小顺序分组等。邪恶的出题人往往把区间开的很大,让我们的暴力解法无法实现,所以我们就需要采用数位 DP 解决。

数位 DP 的基本思想:逐位确定。

练手板子题:P2657

区间 DP

区间类动态规划问题,首先考虑的就是建立一个数组 f ( i , j ) f(i,j) f(i,j) 存储区间内的最优解,然后枚举断点 k k k f ( i , j ) = f ( i , k ) + f ( k + 1 , j ) f(i,j)=f(i,k)+f(k+1,j) f(i,j)=f(i,k)+f(k+1,j)

区间 DP 的解法基本满足:

  1. 枚举区间
  2. 枚举左端点
  3. 枚举断点

区间DP的特点:

  • 合并:合并区间或拆分区间
  • 特征:能将问题转化为区间合并
  • 求解:类似分治

区间DP有一种特殊情况,即环状区间,我们可以把一个长为 n n n 的环转化为 2 n 2n 2n 长的链,枚举 f ( 1 , n ) , f ( 2 , n + 1 ) , ⋯   , f ( n , 2 n − 1 ) f(1,n),f(2,n+1),\cdots,f(n,2n-1) f(1,n),f(2,n+1),,f(n,2n1) 找到最优值即可。

树形 DP(树上背包)

对于一棵树,每个节点上有一个物品,每个体积为 w i w_i wi,价值为 v i v_i vi。选了一个点必须选它的父亲。问总体积不超过 m m m 的情况下总价值最大值。

乍一看,很像一道 01 01 01 背包,但是又有基于树状数据结构的限制条件。

于是乎,我们请出神级 DP 状态设计。

首先我们来一种更加好懂的三维思路。我们设 f ( i , j , k ) f(i,j,k) f(i,j,k) 表示对于根节点为 i i i 的子树,考虑它的前 k k k 棵子树,给它 j j j 的体积,能得到的最大价值。显然这时候, i i i 物品一定要选。显然,当前状态一定是由前 k − 1 k-1 k1 棵子树转移而来,于是乎我们可以用 01 01 01 背包的思想压掉一维。

常见状态转移方程:(注意由于要考虑儿子的状态,所以要先 DFS)

void dfs(int x)
{
    f[x][1]=val[x];
    for(int i=head[x];i;i=nxt[i])
    {
        dfs(to[i]);
        for(int j=M+1;j;j--)
            for(int k=1;k<j;k++)
                f[x][j]=max(f[x][j],f[to[i]][k]+f[x][j-k]);
    }
}

树上背包的时间复杂度证明(来自大佬 @Steven24):

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

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

相关文章

分布式应用开发的核心技术系列之——基于TCP/IP的原始消息设计

本文由葡萄城技术团队原创并首发。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 前言 本文的内容主要围绕以下几个部分&#xff1a; TCP/IP的简单介绍。消息的介绍。基于消息分类的传输格式&…

嵌入式养成计划-46----QT--简易版网络聊天室实现

一百一十九、简易版网络聊天室实现 119.1 QT实现连接TCP协议 119.1.1 基于TCP的通信流程 119.1.2 QT中实现服务器过程 使用QTcpServer实例化一个服务器对象设置监听状态&#xff0c;通过listen()函数&#xff0c;可以监听特定的主机&#xff0c;也可以监听所有客户端&#x…

二维码智慧门牌管理系统升级解决方案:高效、便捷、安全的外业数据管理方法

文章目录 前言一、背景与需求二、升级解决方案三、方案优势 前言 在当今的信息化社会&#xff0c;数据管理的重要性日益凸显。尤其对于像二维码智慧门牌管理系统这样的复杂系统&#xff0c;如何实现高效、便捷、安全的数据管理&#xff0c;成为了系统升级的重要议题。本文将详…

计算机数据库中了malloxx勒索病毒怎么解决,勒索病毒解密,数据恢复

随着网络技术的不断发展&#xff0c;越来越多的网络安全威胁也不断增加&#xff0c;最近&#xff0c;云天数据恢复中心接到一些企业的求助&#xff0c;企业的计算机数据库遭到了malloxx勒索病毒攻击&#xff0c;导致企业所有计算机服务器无法正常使用&#xff0c;针对此次勒索病…

51单片机定时器和中断(03)

eg1&#xff1a;数码管如何显示出字符 51单片机40个引脚的功能需要记住** RXD&#xff1a;表示的是串行输入口INT0&#xff1a;外部中断0INT1&#xff1a;外部中断1TO : 外部中断0T1 &#xff1a;外部中断1WR: 外部输入存储器写RD: 外部输出存储器读XTK2/XTL1 单片机晶振的输…

微信公众号迁移详细步骤

公众号迁移有什么作用&#xff1f;只能变更主体吗&#xff1f;很多小伙伴想做公众号迁移&#xff0c;但是不知道公众号迁移有什么作用&#xff0c;今天跟大家具体讲解一下。首先公众号迁移最主要的就是修改公众号的主体了&#xff0c;比如我们公众号原来是A公司的&#xff0c;现…

Ubuntu 22.04 中安装 fcitx5

Ubuntu 22.04 中安装 fcitx5 可以按照以下步骤进行&#xff1a; 添加 fcitx5 的 PPA 首先&#xff0c;添加 fcitx5 的官方 PPA&#xff1a; sudo add-apt-repository ppa:fcitx-team/fcitx5更新软件包列表 sudo apt update安装 fcitx5 sudo apt install fcitx5 fcitx5-conf…

基于SSM的文化培训学校网站的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

030-第三代软件开发-密码输入框

第三代软件开发-密码输入框 文章目录 第三代软件开发-密码输入框项目介绍密码输入框总结一下 关键字&#xff1a; Qt、 Qml、 echoMode、 TextInput、 Image 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这个项目结合了 QML&#xff08;Qt Meta-Object Language…

【Qt控件之QMdiArea】介绍及使用

描述 QMdiArea小部件提供了一个区域&#xff0c;用于显示MDI窗口。QMdiArea的功能类似于MDI窗口的窗口管理器。例如&#xff0c;它在自身上绘制和排列管理的窗口&#xff0c;可以按级联或平铺模式排列它们。通常&#xff0c;QMdiArea被用作QMainWindow的中心小部件&#xff0c…

YOLOv5算法改进(17)— 手把手教你去更换损失函数(IoU/GIoU/DIoU/CIoU/EIoU/AlphaIoU/SIoU)

前言:Hello大家好,我是小哥谈。损失函数(loss function)是机器学习中用来衡量模型预测值与真实值之间差异的函数。它用于度量模型在训练过程中的性能,以便优化模型参数。在训练过程中,损失函数会根据模型的预测结果和真实标签计算出一个标量值,代表了模型预测的错误程度…

离散低通滤波方法

低通滤波器允许低频信号通过&#xff0c;并抑制高频信号。其核心思想是在频率域上通过移除高频成分来平滑信号。这在去噪、平滑和提取基本频率成分时非常有用。 离散低通滤波方法通常采用一阶低通滤波器进行处理。一阶低通滤波器是一种常见的数字滤波器&#xff0c;能够将信号…

分享 | 对 电商API 平台的再思考

API 是推动现代企业数字化转型的基础。它不但连接了内部应用程序、合作伙伴和客户&#xff0c;同时也快速持续地向市场提供了各种新产品、版本和功能。 但当下还是以集中式的 API 交付为主。一个企业的对外 API 交付过程通常都是冗余而繁琐的&#xff0c;对企业内部的敏捷性、速…

数据丢失恢复怎么操作好?五种方法帮您恢复数据

丢失文件可能会造成灾难性的后果&#xff0c;因此您绝对需要最好的 PC 恢复软件。数据恢复软件必须快速、可靠并涵盖大多数文件格式。我们列表中最好的工具是一个甚至可以检索隐藏文件的解决方案。我们选择的另一个解决方案能够恢复700 多种独特的文件格式。 这种噩梦可能发生…

通过WinSCP实现Windows给Ubuntu(Linux)虚拟机传输数据

要实现传输有几个准备工作需要做 1.在虚拟机运行工具&#xff08;VMware或者其他&#xff09;中设置网络&#xff08;或者网络适配器&#xff09;为桥接模式&#xff08;之前是NAT模式&#xff09; 2.使用ifconfig命令查看虚拟机的网络地址 3.确定虚拟机中安装了ssh 安装 sudo…

数组问题答疑

在对数组有一定了解后我们会遇到一些问题&#xff0c;本文章将尽可能的讲解一些常见错误。 文章目录 1.数组名&#xff0c;&数组名分别代表什么&#xff1f;2.数组形式做形参时是传的整个数组还是首元素地址&#xff1f;3.为什么在主函数中用sizeof(arr)计算出的结果是整个…

登上抖音热搜榜:如何让你的内容火爆全网

在当今信息爆炸的时代&#xff0c;抖音已经成为了很多人获取信息、娱乐和社交的重要平台。每一天&#xff0c;都有大量的短视频在抖音上诞生&#xff0c;然而&#xff0c;只有少数幸运儿能够登上抖音热搜榜&#xff0c;成为万人瞩目的焦点。那么&#xff0c;如何让你的内容火爆…

【设计模式】解释器模式

文章目录 1.解释器模式定义2.解释器模式的角色3.解释器模式实战案例3.1.场景说明3.2.结构类图3.3.代码实现 4.解释器模式优缺点5.解释器模式适用场景6.解释器模式总结 主页传送门&#xff1a;&#x1f481; 传送 1.解释器模式定义 解析器模式&#xff08;Interpreter Pattern&a…

我国跨境电商行业研究报告(2022)

我国跨境电商行业研究报告 我国跨境电商规模突飞猛进&#xff0c;2022年进出口规模超2万亿元&#xff0c;2023年上半年跨境电商出口8210亿元&#xff0c;增长19.9%。全国跨境电商主体已超10万家&#xff0c;近年来涌现出一批上市公司&#xff0c;以及广州希音等全球独角兽企业。…

Java后端模拟面试 题集④

1.你先作个自我介绍吧 面试官您好&#xff0c;我叫张睿超&#xff0c;来自湖南长沙&#xff0c;大学毕业于湖南农业大学&#xff0c;是一名智能科学与技术专业的统招一本本科生。今天主要过来面试贵公司的Java后端开发工程师岗位。 大学里面主修的课程是Java、Python、数字图…