浅谈数位DP

动态规划,是OI中极其重要的一环。
由于它的重要性,解决问题的广泛性,它衍生出了多种多样的DP。
其中,有一种特别搞人的叫做数位DP

思想

数位DP是通过每一位数字去递推,来统计从在 [0,a] 中,有多少个数满足条件或者有多少种满足某一条件的方案数。
由于有一个统计的上界,所以对我们的DP会有所限制:
当你从低位往高位扫,你不一定能确定到了高位它会不会被限制;
当你从高位往低位扫,你不一定能确定到了低位它需不需要限制。
但是,有一类数位DP却是无拘无束:
Luogu P2106 Sam数
虽然它并不是严格意义上的数位DP(比如Luogu就没有给它数位DP的Tag),但是,它对我们做数位DP是很有启发意义的
为什么这道看着是数位DP的题目这么简单?
因为它题目说的是:

他将一个 k 位 Sam 数称之为 k 阶 Sam 数

一行一个整数 ans,表示 k 阶的 Sam 数的个数

因为它只要求了位数,或者说它要求的区间是 [10k1,10k)
我们的唯一限制是位数是定下来的,每一位是0还是9我们并不关心(当然除了前导0蛤),并没有在每一位上面有什么好纠结的。
这时候我们就想了,既然只对位数有要求,或者只对首位有要求的都比较好求解,那我们是不是可以考虑把我们的问题拆分成若干个这样子的问题呢?
显然是可以的。

核心

对于 A=anan1a2a1 我们要统计 [0,A] 中满足条件的数的个数,我们可以把它划分成若干个问题
[0,A]=[0,an10n1)[an000,anan1000)[anan1a20,anan1a2a1){anan1a2a1}
这是它数学的拆分,或者我们把它理解成这样:
前几位锁定了,中间某一位可以从 0ak 选择,后面几位任意选
那么,前几位对于要求的影响是可以提前处理掉的,而且在接着往后处理的时候可以直接继承。
只需要枚举中间的一位,可以用数学或者其他的方法知道有多少可行的数字。
在这里讲道理只能知道思想,重点还是要去看题目。

代码实现

由于数位DP一般都是统计 [l,r],由于同时有上下界,我们很难搞,一般就会转化成 [0,r][0,l1] (也有可能不取0)
所以一般数位DP都会是在一个int solve(int num)函数中解决问题
其次,由于我们是一位一位处理的,所以我们一般会对num在进行按位拆分,可能是十进制,也可能是二进制,甚至是K进制,当然,这也是因题而异。

例题

  1. Luogu P2657 [SCOI2009] windy 数
    乍一看,这就是Sam数的逆反版,相邻两位数的差必须得大于等于2。
    那么我们考虑,加入被锁定了前几位,枚举这一位的可行情况:首先,被锁定的前几位要满足条件;其次,这一位枚举的数要和上一位满足条件;最后后几位要满足条件。
    考虑先预处理一个二维数组 fi,j 表示共 j 位,最高位为 i 的Windy数个数。
    这个的转移方程式显然的:fi,j=k=09[|kj|2]fk,j1
    不难发现,如果锁定前 i 位不满足Windy数要求,那么锁定前 i+1 位也必然不满足,所以我们可以进行一次小优化
  2. Luogu P4317 花神的数论题
    由于题目要求和二进制有关,所以我们可以把原数按二进制拆分。
    要求1到N所有数的二进制形式中1的个数的和的成绩,考虑转化为统计一共有多少个在1到N之间的数,他们的二进制形式中有k个1,那么它对答案的贡献就是 knum
    前几位锁定了就确定了1的个数,如果当前位是0,没得可以选,直接跳过;遇到当前位为1的,可以讨论一下如果这一位是0,会有多少贡献,可以用组合数进行数学优化
  3. Luogu P4127 [AHOI2009]同类分布
    这道题目要求各位数字之和能整除原数的数的个数,所以我们考虑额外统计一个数:代表它的各位数字之和。
    但是我们会发现,随着位数的推移,各位数字之和也会改变,导致我们通过取模优化空间十分的困难。
    如果各位数字之和确定了,那该多好……所以我们可以枚举各位数字之和,看既满足各位数字之和、又满足能被各位数字之和整除的有多少个即可

优化

有的时候,我们需要存储很多的信息,这种时候优化就很重要了

仍然是栗子

Luogu P3303 [SDOI2013] 淘金
这个题目很显然在数位DP的基础之上,还要求各位数字之积,考虑上界 9122.821011 很显然存下来是不现实的。
但仔细想想,比如就不可能存在各位数字之积是11的,是不是说其实有很多的空间是无用的呢——是的
各位数字之积,作为乘数的只有0到9。0是一个bug可以不考虑,那么其他的9个数只可能存在4种质因子:2,3,5,7
由于位数只有12位,所以我们也很容易计算出它的上界 812=236,912=324,512,712
只需要在用滚动数组再优化一下空间就可以轻松地解决掉这道题了

posted @   Xun_Xiaoyao  阅读(152)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
/* 鼠标点击求赞文字特效 */
点击右上角即可分享
微信分享提示