动态规划——数位dp

news2024/11/28 15:45:35

数位dp

文章目录

  • 数位dp
    • 概述
      • 题目特征
      • 基本原理
      • 计数技巧
    • 模板
    • 例题
      • 度的数量
        • 思路
        • 代码
      • 数字游戏
        • 思路
        • 代码
      • 不要62
        • 思路
        • 代码

概述

数位是指把一个数字按照个、十、百、千等等一位一位地拆开,关注它每一位上的数字。如果拆的是十进制数,那么每一位数字都是 0~9,其他进制可类比十进制。

题目特征

数位 DP:用来解决一类特定问题,这种问题比较好辨认,一般具有这几个特征:

  1. 要求统计满足一定条件的数的数量(即,最终目的为计数);

  2. 这些条件经过转化后可以使用「数位」的思想去理解和判断;

  3. 输入会提供一个数字区间(有时也只提供上界)来作为统计的限制;

  4. 上界很大(比如 ),暴力枚举验证会超时。

基本原理

考虑人类计数的方式,最朴素的计数就是从小到大开始依次加一。但我们发现对于位数比较多的数,这样的过程中有许多重复的部分。例如,从 7000 数到 7999、从 8000 数到 8999、和从 9000 数到 9999 的过程非常相似,它们都是后三位从 000 变到 999,不一样的地方只有千位这一位,所以我们可以把这些过程归并起来,将这些过程中产生的计数答案也都存在一个通用的数组里。此数组根据题目具体要求设置状态,用递推或 DP 的方式进行状态转移。

计数技巧

数位 DP 中通常会利用常规计数问题技巧,比如把一个区间内的答案拆成两部分相减(即 a n s [ l , r ] = a n s [ 0 , r ] − a n s [ 0 , l − 1 ] \mathit{ans}_{[l, r]} = \mathit{ans}_{[0, r]}-\mathit{ans}_{[0, l - 1]} ans[l,r]=ans[0,r]ans[0,l1]

模板

在这里插入图片描述

# 假设n为b进制数
def dp(n) :
	# 特判数为0,防止下面把每位提出时的bug
	if not n : return ..
	nums = []
	while n :
		nums.append(n % b)
		n //= b
	res, last = 0, 0 #分别存储上结果和前面位的对当前位的有用信息
	for i in range(len(nums) - 1, -1, -1) : #对每一位进行枚举
		for j in 除上界以外可能的数 :
			if 进行可行性判断 :
				res += 预处理的数
		#当第i为取上界时,判断可行性再进行下一轮
		if not i and 判断是否可行 : res += 1
	return res

例题

度的数量

求给定区间 [X,Y] 中满足下列条件的整数个数:这个数恰好等于 K 个互不相等的 B 的整数次幂之和。

例如,设 X=15,Y=20,K=2,B=2,则有且仅有下列三个数满足题意:

17=24+20
18=24+21
20=24+22
输入格式
第一行包含两个整数 X 和 Y,接下来两行包含整数 K 和 B。

输出格式
只包含一个整数,表示满足条件的数的个数。

数据范围
1≤X≤Y≤231−1,
1≤K≤20,
2≤B≤10
输入样例:
15 20
2
2
输出样例:
3

思路

分类讨论,当枚举的位数处于第i位时 x i x_i xi的情况,当N的第i位为x:

  1. 当x = 0时:则 x i x_i xi只能取0,即上界的情况,则继续向下枚举即可
  2. 当x = 1时:则 x i x_i xi取上界以外的情况只能是取0,此时低位的数可以随意填写,但必须满足题目中1的总个数等于k的前提下。随后取 x i = 1 x_i = 1 xi=1,继续向低位枚举。
  3. 当x > 1时:则 x i x_i xi取上界以外的情况只可以是0、1,此时低位的数可以随意填写,但必须满足题目中1的总个数等于k的前提下。但 x i x_i xi永远碰不到上界,则无需向低位枚举。

注意:当枚举到第i位时,已经使用了last个1,如果是未取上界的情况,那么剩下的i位低位中剩余k-last个1可用随便放。是个组合数,可以预处理出来。

代码

N = 35
f = [[0] * N for _ in range(N)]

def init() : #预处理出组合数
	for i in range(N) :
		for j in range(N) :
			if j == 0 :
				f[i][j] = 1
			else :
				f[i][j] = f[i - 1][j - 1] + f[i - 1][j]

def dp(n) :
	# 特判0
	if not n : return 0
	nums = []
	#处理出n在b进制下的每一位的数
	while n : 
		nums.append(n % b)
		n //= b
	res, last = 0, 0 #分别记录结果和高位对1的使用情况
	for i in range(len(nums) - 1, -1, -1) : #从高位往低位枚举
		x = nums[i] #取出n中第i位的数
		if x : #当0不是上界
			res += f[i][k - last] #第i位为0的情况
			#当上界大于1的情况
			if x > 1 :
				if k - last - 1 >= 0 : 
					res += f[i][k - last - 1]
				break
			# 取上界为1时
			else :
				last += 1
				if last > k : break
		if not i and last == k : res += 1
	return res
	
init()			
l, r = map(int, input().split())
k = int(input())
b = int(input())
print(dp(r) - dp(l - 1))

数字游戏

科协里最近很流行数字游戏。

某人命名了一种不降数,这种数字必须满足从左到右各位数字呈非下降关系,如 123,446。

现在大家决定玩一个游戏,指定一个整数闭区间 [a,b],问这个区间内有多少个不降数。

输入格式
输入包含多组测试数据。

每组数据占一行,包含两个整数 a 和 b。

输出格式
每行给出一组测试数据的答案,即 [a,b] 之间有多少不降数。

数据范围
1≤a≤b≤231−1
输入样例:
1 9
1 19
输出样例:
9
18

思路

分类讨论,当枚举的位数处于第i位时 x i x_i xi的情况,当N的第i位为x:

  1. x i = x x_i = x xi=x时,即取上界时,如果合法,则继续向更低位开始枚举。
  2. x i < x x_i < x xi<x时,则更低位的数应该是所有以 [ l a s t , x ) [last, x) [last,x)为最高位的i + 1位数的非下降的数

last为上一位的上界即 x i + 1 x_{i + 1} xi+1

预处理:
状态表示:
集合:f[i, j]表示最高位为j的i位的非下降的数的集合
属性:num
状态计算: f [ i , j ] = ∑ j 9 f [ i − 1 , k ] f [i, j] = \sum_j^9 f[i - 1, k] f[i,j]=j9f[i1,k]

代码

N = 15

f = [[0] * N for _ in range(N)]

# 预处理出最高位为j的i位的非下降的数的数量
def init() :
	for i in range(10) : f[1][i] = 1
	for i in range(2, N) :
		for j in range(10) :
			for k in range(j, 10) :
				f[i][j] += f[i - 1][k]

def dp(n) :
	# 特判0,有一个数满足条件
	if not n : return 1
	nums = []
	#处理出n的每一位,存于nums中
	while n :
		nums.append(n % 10)
		n //= 10
	res, last = 0, 0 #last存储上一层的数
	# 从高到低枚举每一位
	for i in range(len(nums) - 1, -1, -1) :
		x = nums[i]
		if last > x : break #如果当前位能取到的最大的数小于上一层上界,则退出
		#x_i不取上界
		for j in range(last, x) :
			res += f[i + 1][j]
		#取上界
		last = x
		if not i : res += 1 #特判最后一个数
	return res
			
init()
while True :
	try :
		l, r = map(int, input().split())
	except : break
	print(dp(r) - dp(l - 1))

不要62

杭州人称那些傻乎乎粘嗒嗒的人为 62(音:laoer)。

杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。

不吉利的数字为所有含有 4 或 62 的号码。例如:62315,73418,88914 都属于不吉利号码。但是,61152 虽然含有 6 和 2,但不是 连号,所以不属于不吉利数字之列。

你的任务是,对于每次给出的一个牌照号区间 [n,m],推断出交管局今后又要实际上给多少辆新的士车上牌照了。

输入格式
输入包含多组测试数据,每组数据占一行。

每组数据包含一个整数对 n 和 m。

当输入一行为“0 0”时,表示输入结束。

输出格式
对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。

数据范围
1≤n≤m≤109
输入样例:
1 100
0 0
输出样例:
80

思路

分类讨论,当枚举的位数处于第i位时 x i x_i xi的情况,当N的第i位为x:

  1. x i = x x_i = x xi=x时,即取上界时,如果合法(不等于4且last与 x i x_i xi不等于62),则继续向更低位开始枚举。
  2. x i < x x_i < x xi<x时,则更低位的数应该是所有以 [ 0 , x ) [0, x) [0,x)为最高位的i + 1位数合法的数

last为上一位的上界即 x i + 1 x_{i + 1} xi+1

预处理:
状态表示:
集合:f[i, j]表示最高位为j的i位的吉利的号码的集合
属性:num
状态计算: f [ i , j ] = ∑ 0 9 f [ i − 1 , k ] f [i, j] = \sum_0^9 f[i - 1, k] f[i,j]=09f[i1,k]

代码

N = 10

f = [[0] * N for _ in range(N)]
# 预处理 f[i, j]表示最高位为j的i位的吉利的号码的集合的数目
def init() :
	for i in range(10) :
		if i == 4 : continue
		f[1][i] = 1
	for i in range(2, N) :
		for j in range(10) :
			if j == 4 : continue
			for k in range(10) :
				if k== 4 or (j == 6 and k == 2) : continue
				f[i][j] += f[i - 1][k]

def dp(n) :
	if not n : return 1
	nums = []
	while n :
		nums.append(n % 10)
		n //= 10
	res, last = 0, 0
	# 从高到低枚举每一位
	for i in range(len(nums) - 1, -1, -1) :
		x = nums[i]
		# x_i不取上界
		for j in range(x) :
			# 判断是否合法
			if j == 4 or (last == 6 and j == 2) :
				continue
			res += f[i + 1][j]
		# 当取上界x不合法时,则退出
		if x == 4 or (last == 6 and x == 2) : break
		last = x
		# 特判数为n时
		if not i : res += 1
	return res
init()
while True :
	l, r = map(int, input().split())
	if l == 0 and r == 0 : break
	print(dp(r) - dp(l - 1))

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

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

相关文章

unity 前向渲染 渲染阴影原理

下面情况默认是 前向渲染路径&#xff0c;场景中平行光开启了阴影方式原理备注ShadowMap把相机放到光源的位置&#xff0c;那么场景中该光源的阴影区域就是那些相机看不到的位置得到的是&#xff1a;场景中距离光源最近的表面位置&#xff08;深度信息&#xff09;unity中专门的…

一个基于SpringBoot+vue的学生信息管理系统详细设计

一个基于SpringBootvue的学生信息管理系统详细设计 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码…

【docker08】本地镜像发布到阿里云

本地镜像发布到阿里云流程 1.流程 2.镜像的生成方法 基于当前容器创建一个新的镜像&#xff0c;新功能增强命令&#xff1a; docker commit [OPTIONS] 容器ID [REPOSITORY[:TAG]] 3.将本地镜像推送到阿里云 3.1本地镜像素材原型 3.2阿里云开发者平台 进入阿里云找到控制台进…

Word控件Spire.Doc 【Table】教程(2):如何设置Word表格列宽

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

CV中一些常见的特征点

Harris、SIFT、SURF、ORB特征点总结本篇博客介绍一些常见的特征点。Brief描述子&#xff1a;编辑切换为居中添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09;编辑切换为居中添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09;编辑切换为居…

基于JavaSpringboot+Vue实现前后端分离房屋租赁系统

基于JavaSpringbootVue实现前后端分离房屋租赁系统 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码…

已解决Python pandas.read_excel读取Excel文件报错

已解决&#xff08;Python pandas.read_excel读取Excel文件报错&#xff09;io ExcelFile(io&#xff0c;storage_optionsstorage.options, engineengine) 文章目录报错代码报错原因解决方法帮忙解决报错代码 粉丝群一个小伙伴想用pandas.read_excel读取Excel文件&#xff…

Linux文件管理---磁盘上文件如何管理(inode)

文章目录磁盘与文件的关系磁盘的逻辑结构与操作系统关系真实的磁盘逻辑结构一台计算机磁盘上的文件是非常多的&#xff0c;这些文件该如何进行管理&#xff1f;我们想打开某个磁盘上的文件究竟是如何找到该文件的&#xff1f;磁盘与文件的关系 这就是磁盘的物理模型和存储结构 …

Ubuntu20.04安装Mysql5.7

目录 1、下载安装包 2、解压 3、删除测试安装包 4、开始安装Mysql 4.1、如果碰到缺少依赖处理方法&#xff0c;没有碰到忽略即可 5、配置MySQL 5.1、查看mysql状态 5.2、设置root密码 1、下载安装包 wget https://cdn.mysql.com/archives/mysql-5.7/mysql-server_5.7.3…

操作系统死锁相关知识点介绍

死锁 死锁的定义 一组进程中&#xff0c;每个进程都无限等待被该组进程中另一进程所占有的资源&#xff0c;因而永远无法得到的资源&#xff0c;这种现象称为进程死锁&#xff0c;这一组进程就称为死锁进程。 如果死锁发生&#xff0c;会浪费大量系统资源&#xff0c;甚至导致…

【CSDN周赛】第21期第二题千问万问

题目描述&#xff1a; 给定大小为n的整数序列A. 现在会有q次询问&#xff0c;询问子区间的整数数量。 思路&#xff1a; 1、考的时候没做出来&#xff0c;但是感觉不难&#xff0c;一直不懂错在哪里&#xff0c;所以比赛结束后继续修改&#xff1b; 2、以下代码没有按调用函…

QTextDocument

一、描述 此类用来储存结构化的富文本文档。 二、类型成员 1、enum QTextDocument::FindFlag&#xff1a;此枚举描述查找函数可用的选项。这些选项可以用“|”组合&#xff1a; FindBackward&#xff1a;向后搜索。FindCaseSensitive&#xff1a;不区分大小写。FindWholeWo…

用户单点登录

一、用户身份认证 1、单一服务器模式 我们使用传统的Session贺Coookie的模式&#xff0c;就可以完成单一服务器的登录&#xff0c;会话跟踪技术&#xff0c; 一般过程如下&#xff1a; 用户向服务器发送用户名和密码。 验证服务器后&#xff0c;相关数据&#xff08;如用户名…

SpringBoot自定义动态定时任务(三十五)

二八佳人体似酥&#xff0c;腰间仗剑斩愚夫。虽然不见人头落&#xff0c;暗里教君骨髓枯。 上一章简单介绍了SpringBoot整合Quartz实现动态定时任务(三十四) ,如果没有看过,请观看上一章 通过 Quartz 实现了动态定时任务&#xff0c;还需要引入 Quartz 组件&#xff0c; 能不…

腾讯前端二面高频手写面试题总结

实现LRU淘汰算法 LRU 缓存算法是一个非常经典的算法&#xff0c;在很多面试中经常问道&#xff0c;不仅仅包括前端面试 LRU 英文全称是 Least Recently Used&#xff0c;英译过来就是” 最近最少使用 “的意思。LRU 是一种常用的页面置换算法&#xff0c;选择最近最久未使用的…

降本提效 | AIRIOT设备运维管理解决方案

传统运维多是使用在本地化系统&#xff0c;以人工运维和独立系统执行运维工作&#xff0c;重点关注的是设施运行&#xff0c;存在以下几个问题&#xff1a; 1、信息孤岛&#xff1a;本地化系统的接口不同&#xff0c;功能单一独立&#xff0c;各个系统之间的数据无法对接、交互…

了解枚举。

在数学和计算机科学理论中&#xff0c;一个集的枚举是列出某些有穷序列集的所有成员的程序&#xff0c;或者是一种特定类型对象的计数。这两种类型经常&#xff08;但不总是&#xff09;重叠。 [1] 是一个被命名的整型常数的集合&#xff0c;枚举在日常生活中很常见&#xff0…

xxx.OpenResty+Lua后续补充

OpenRestyLua后续补充-请求参数处理看上图&#xff0c;鼠标右键-在新标签中打开图片食用 这是对xxx.nginx转发OpenResty(nginx升级版)_web服务器lua_tgbyhn31的博客-CSDN博客 的一个补充&#xff0c;用于nginx处理请求参数。 附代码&#xff1a; nginx 配置 #user nobody; w…

centos7 安装docker和docker-compose

本人使用的是 阿里云的centos7 的 镜像 安装在虚拟机里面的linux系统 curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun 如果这条命令没用 在国内很慢 换个地址用下面的试试 curl -sSL https://get.daocloud.io/docker | sh 安装成功 设置开机启动doc…

让你轻松掌握电商设计的在线工具,无门槛

零门槛不用经过工具认识&#xff0c;跟着教程就能上手的电商主图设计平台&#xff0c;让无基础又急需要设计电商主图的你轻松设计商品主图&#xff0c;下面跟着小编的教程一起学习如何使用乔拓云&#xff0c;在线设计电商主图&#xff01;按照步骤就能搞定&#xff01;第一步&a…