数据结构与算法-动态规划-数位dp(计数问题,度的数量,数字游戏,windy数,数字游戏2,不要62,恨7不成妻)

数位dp

数位 DP 是一种基于动态规划思想,专门用于解决与数字的各个数位相关问题的算法技巧。以下从其定义、适用场景、解题步骤等方面进行介绍:

定义:

数位 DP 通过对数字的每一位进行分析和处理,利用动态规划的方法来解决问题。它将数字看作是由一个个数位组成的序列,通过对这些数位上数字的取值和组合进行分析,从而解决与数字特征相关的计数、求和等问题。

常用技巧,一般都是让我们去求[l,r]区间上的满足某个要求的个数,我们通常是用前缀和的思想,f(x~y)=f(1~y) - f(1~x)

应用:

区间计数问题:例如,计算给定区间 [L, R] 内满足某种数位特征(如数字中不含 4 和 62)的整数个数。像在一个城市的车牌号码中,规定不能出现 4 和 62 这样的数字组合,要统计符合规定的车牌数量,就可使用数位 DP。

数位特征求和问题:比如,求区间 [1, N] 内所有数的各位数字之和。假设要统计从 1 到 10000 所有数字的各位数字之和,数位 DP 就能发挥作用。

数字排列组合问题:给定一些数位的限制条件,计算满足这些条件的数字排列组合方式。例如,规定一个数字的首位不能为 0,且相邻数位的差值不能超过 2,求满足条件的数字个数。

解题步骤:

确定状态:这是数位 DP 的关键。通常,状态会与当前处理的数位位置、前面数位的状态以及一些限制条件相关。例如,定义 dp[pos][state] 表示处理到第 pos 个数位时,前面数位形成的某种状态为 state 时的结果。这里的 state 可以是前面数位的和、是否出现过特定数字组合等。比如在计算不含 4 和 62 的数字个数时,state 可以是一个表示前面是否出现过 6 的布尔值,若出现过 6,后续数位不能为 2。

状态转移:根据问题的性质和数位的取值范围,确定如何从已有的状态推导出新的状态。比如,在处理下一位数字时,考虑当前位数字的取值对前面状态的影响,从而更新状态。假设当前处理到第 pos 位,若当前位数字为 i,且前面状态为 state,根据问题的规则,可能会转移到新的状态 new_state,那么 dp[pos][new_state] 就需要根据 dp[pos - 1][state] 进行更新。例如,在计算各位数字之和的问题中,dp[pos][sum] 可能会根据 dp[pos - 1][sum - i] 进行更新,其中 i 是当前位的数字。

边界条件:确定初始状态和边界情况。例如,当处理到最高位(即 pos 为 0)时,初始状态可能是一些特定的值,比如在计数问题中,初始状态可能为 1,表示空数字也算一种情况。又如,在计算各位数字之和的问题中,初始状态可能为 0。

记忆化搜索或递推:

记忆化搜索:通过递归的方式从高位到低位处理数字,在递归过程中,若遇到已经计算过的状态(即 dp[pos][state] 已经有值),直接返回该值,避免重复计算。例如,当计算到 dp[3][5] 时,如果之前已经计算过,就不再重新计算,直接返回结果。

递推:从低位到高位依次计算每个状态的值。先计算最低位的所有可能状态,然后根据状态转移方程,逐步计算更高位的状态。例如,先计算个位的各种状态,再根据个位的结果计算十位的状态,以此类推。

结果计算:根据题目要求,结合计算得到的状态值,得出最终的结果。例如,在区间计数问题中,可能需要将满足条件的所有状态值相加,得到区间内满足条件的数字个数。

引例(计数问题):

分析:


问题描述这是一道颇具趣味的数字统计类题目。从解题的角度来看,由于数字范围可能较大,简单地逐个数字遍历并统计每个数位上的数字可能效率较低。可以考虑运用数位 DP(动态规划)的方法,通过对数字的数位进行分析和状态转移来高效地解决该问题。当然任务:统计 a和 b之间(包含 a和b)所有数字中 0-9每个数字的出现次数。例如  a=1024,b=1032,需统计这之间这 9 个数中 0-9 各自的出现次数。

这里可以实现一个函数count(n,x),求出1~n中,数字x出现的次数,那么a~b之间x出现的次数就是count(b,x)-count(a,x)

下面思考如何实现count(n,x)

假设一个数n是abcdefg,7位数,求出1在第4位的数的出现次数也就是xxx1xxx在(1,abcdefg)出现的次数,也就是 1<=xxx1xxx<=abcdefg,下面来分类讨论

--1:左边三位数abc

----1:如果x是0,取1~abc-1,右边三位数efg任意取数

----2:如果x不是0,取0~abc-1,右边三位数efg任意取数

--2:左边三位数为abc

----1:d>x,如果abc和x不同时为0,后面的xxx取0~999任意取数

----2:d==x,如果abc和x不同时为0,后面的xxx取0~efg

伪代码:

练习1(度的数量):

分析:


这是一道基于数位特征进行计数的问题,可运用数位 DP(动态规划)方法求解,以下从问题描述、解题思路等方面介绍:

输入参数:给定区间 X,Y ,以及整数 k和 B。其中,X 和 Y 确定了数字的取值范围, 表示满足条件的数需由 K 个互不相等的 B的整数次幂相加得到,B 是幂运算的底数。

任务目标:统计在区间「X, Y]中,恰好能表示为 K 个互不相等的 B的整数次幂之和的整数个数。

示例说明:当X=15,Y=20,K=2,B=2时,17=2^4+2^0,18=2^4+2^1,20=2^4+2^2 这三个数满足条件,即区间内满足条件的整数个数为3。

举例:

所以这里的f[i][j]就是组合数,表示从i个数中选择j个数字的方案数

伪代码:

练习2(数字游戏):

分析:

这是一道典型的数位统计计数问题,常运用数位动态规划(数位 DP)的方法来求解。以下从问题背景、核心要求、解题思路等方面进行介绍:

在科协的数字游戏情境中,定义了一种特殊的数字 —— 不降数。

不降数定义:从左到右各位数字呈非下降关系的数,例如 123(1≤2≤3)、446(4≤4≤6)等都是不降数。

任务目标:给定一个整数闭区间 [a, b],要求统计出这个区间内不降数的个数。

我们还是先定义一下我们的dp[i],表示从0~i有多少个不降数

伪代码:

习题3(windy数):

分析:

这是一道基于数字特征计数的问题,常借助数位动态规划(数位 DP)来解决,以下从问题定义、任务要求、解题思路等方面介绍:

Windy 数定义:Windy 定义了一种特殊的数,即不含前导零,并且相邻两个数字之差至少为 2 的正整数被称为 Windy 数。例如,135 是 Windy 数(1 和 3 差为 2,3 和 5 差为 2 ),而 123 不是(2 - 1 = 1<2 )。

给定两个数 A 和 B,要求统计在 A 和 B 之间(包含 A 和 B)总共有多少个 Windy 数。

伪代码:

习题4(数字游戏2):

分析:


这是一道典型的数位统计类问题,通常可利用数位动态规划(数位 DP)的方法来求解。以

在科协流行数字游戏的情境下,定义了一种新的特殊数字类型 —— 取模数。定义:取模数是指满足各位数字之和对  N取模(即mod N  )结果为 0 的数。例如,若N==3  ,数字12  是取模数,因为其各位数字之和1+2=3,3 mod 3 =0目标:给定一个整数闭区间  ,要求统计出这个区间内取模数的个数。

伪代码:

习题5(不要62):

分析:

这是一道基于数字特征进行计数的问题,通常可借助数位动态规划(数位 DP)或简单的模拟枚举方法来解决。

在杭州,交通管理局扩充出租车牌照,因考虑到部分司机和乘客的心理因素,规定新牌照不再包含不吉利数字。

以杭州方言中对某些人的称呼 “62(音:laoer)” 为背景设定不吉利数字相关规则。

不吉利数字定义:所有含有数字 4 或数字组合 62 的号码为不吉利数字。例如,62315、73418、88914 都属于不吉利号码;而 61152 虽然含有 6 和 2,但并非连号,不属于不吉利数字。

给定一个牌照号区间  ,需要统计出该区间内吉利数字(即不含 4 和 62 的数字)的个数,以此推断交通局今后实际能给多少辆新出租车上牌。

还是和上面的题目一样,从高位向低位划分数字,因为更加的简单,所以直接看代码

伪代码:

f[i][j]表示一共i位,最高位为j,并且吉利的数字组合的个数

习题6(恨7不成妻)

分析:

这是一道结合数字特征判断与求和计算的问题,核心在于找出特定区间内满足条件的整数并计算其平方和

以吉哥单身且讨厌情人节引出,因情人节相关数字(214、77)与 7 有关联,从而使吉哥讨厌一切和 7 有关的数。

若一个整数符合以下三个条件之一,则称其和 7 有关:

整数中某一位是 7;

整数的每一位数字相加的和是 7 的整数倍;

这个整数是 7 的整数倍。

给定一个区间,要求找出该区间内和 7 无关的整数,并计算这些整数的平方和。

那么这里的预处理目标就是预处理出来f[i][j],一共i位,最高位为j的与7无关的数的个数

伪代码:


预处理出来f数组和10的n次方mod7的数组 和 10的n次方mod (1e9+7)的数组

其他dp部分

答案是dp(b)-dp(a-1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值