浅谈数位DP
动态规划,是OI中极其重要的一环。
由于它的重要性,解决问题的广泛性,它衍生出了多种多样的DP。
其中,有一种特别搞人的叫做数位DP
思想
数位DP是通过每一位数字去递推,来统计从在
由于有一个统计的上界,所以对我们的DP会有所限制:
当你从低位往高位扫,你不一定能确定到了高位它会不会被限制;
当你从高位往低位扫,你不一定能确定到了低位它需不需要限制。
但是,有一类数位DP却是无拘无束:
Luogu P2106 Sam数
虽然它并不是严格意义上的数位DP(比如Luogu就没有给它数位DP的Tag),但是,它对我们做数位DP是很有启发意义的
为什么这道看着是数位DP的题目这么简单?
因为它题目说的是:
他将一个 k 位 Sam 数称之为 k 阶 Sam 数
一行一个整数 ans,表示 k 阶的 Sam 数的个数
因为它只要求了位数,或者说它要求的区间是
我们的唯一限制是位数是定下来的,每一位是0还是9我们并不关心(当然除了前导0蛤),并没有在每一位上面有什么好纠结的。
这时候我们就想了,既然只对位数有要求,或者只对首位有要求的都比较好求解,那我们是不是可以考虑把我们的问题拆分成若干个这样子的问题呢?
显然是可以的。
核心
对于
这是它数学的拆分,或者我们把它理解成这样:
前几位锁定了,中间某一位可以从
那么,前几位对于要求的影响是可以提前处理掉的,而且在接着往后处理的时候可以直接继承。
只需要枚举中间的一位,可以用数学或者其他的方法知道有多少可行的数字。
在这里讲道理只能知道思想,重点还是要去看题目。
代码实现
由于数位DP一般都是统计
所以一般数位DP都会是在一个int solve(int num)
函数中解决问题
其次,由于我们是一位一位处理的,所以我们一般会对num在进行按位拆分,可能是十进制,也可能是二进制,甚至是K进制,当然,这也是因题而异。
例题
- Luogu P2657 [SCOI2009] windy 数
乍一看,这就是Sam数的逆反版,相邻两位数的差必须得大于等于2。
那么我们考虑,加入被锁定了前几位,枚举这一位的可行情况:首先,被锁定的前几位要满足条件;其次,这一位枚举的数要和上一位满足条件;最后后几位要满足条件。
考虑先预处理一个二维数组 表示共 位,最高位为 的Windy数个数。
这个的转移方程式显然的:
不难发现,如果锁定前 位不满足Windy数要求,那么锁定前 位也必然不满足,所以我们可以进行一次小优化 - Luogu P4317 花神的数论题
由于题目要求和二进制有关,所以我们可以把原数按二进制拆分。
要求1到N所有数的二进制形式中1的个数的和的成绩,考虑转化为统计一共有多少个在1到N之间的数,他们的二进制形式中有k个1,那么它对答案的贡献就是
前几位锁定了就确定了1的个数,如果当前位是0,没得可以选,直接跳过;遇到当前位为1的,可以讨论一下如果这一位是0,会有多少贡献,可以用组合数进行数学优化 - Luogu P4127 [AHOI2009]同类分布
这道题目要求各位数字之和能整除原数的数的个数,所以我们考虑额外统计一个数:代表它的各位数字之和。
但是我们会发现,随着位数的推移,各位数字之和也会改变,导致我们通过取模优化空间十分的困难。
如果各位数字之和确定了,那该多好……所以我们可以枚举各位数字之和,看既满足各位数字之和、又满足能被各位数字之和整除的有多少个即可
优化
有的时候,我们需要存储很多的信息,这种时候优化就很重要了
仍然是栗子
Luogu P3303 [SDOI2013] 淘金
这个题目很显然在数位DP的基础之上,还要求各位数字之积,考虑上界
但仔细想想,比如就不可能存在各位数字之积是11的,是不是说其实有很多的空间是无用的呢——是的
各位数字之积,作为乘数的只有0到9。0是一个bug可以不考虑,那么其他的9个数只可能存在4种质因子:2,3,5,7
由于位数只有12位,所以我们也很容易计算出它的上界
只需要在用滚动数组再优化一下空间就可以轻松地解决掉这道题了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!