数位DP——小结及模板

一、数位DP

用于解决 范围 [L, R] 内满足某些条件的数有多少 的问题,所谓数位,就是指数的个位、十位、百位、千位…

一般会将先将求ans [L, R] 转化为求 ans [0, R] - ans [0, L-1] ,从而问题就变为数位DP求解 ans [0, X]

数位DP最重要的是状态的构建,而具体DP的过程则是利用DFS+记忆化搜索实现,这样更好理解并实现,而状态的构建则更像是状态的压缩,将 [0, X]的状态根据题意进行压缩。



二、状态构建样例

不要62 HDU - 2089
该题要求数中不含’4’不含连续的 '62’

不含’4’可以在DFS中直接限制,而不含连续的 ‘62’ 需要构建状态:dp[pos][pre_is_six]

因为对于 pos 之后的数位的状态,只有前一位为’6’(之后不可接’2’)前一位不为’6’(之后可接’2’) 这两种状态。


Round Numbers POJ - 3252
该题要求数的二进制形式0的数量不少于1的数量

首先要以二进制形式对X进行拆分,然后同样的进行数位DP

构建状态:dp[pos][cnt0][cnt1]

到达递归边界cnt0>=cnt1时,return 1; 否则 return 0;
同时要注意记录前导零,因为若当前0是前导零时,不能令cnt0+1


B-number HDU - 3652
该题要求数中含有连续的’13’,且数能被13整除

构建状态:dp[pos][pre_is_one][ok][[rem]

pre_is_one记录前一个位是否为1,ok记录是否已有连续的’13’,从而保证第一个条件

对于第二个条件,能被13整除

首先我们知道在DFS过程中,产生一个数是通过不断的 num = num*10 + i 得到的,最后再判断 num%13是否为0,但是num会很大,状态太多无法记录。

而由求模运算的性质可以知道,我们可以每次对num进行求模,而最后的结果并不会改变,那么就可以用rem每次记录num%13的状态,那么就变成了每次 rem = ( rem*10 + i ) % 13

最后到达边界且 ok&&rem==0时,return 1; 否则 return 0;



含有/不含有某些数,含由多少个某些数,能够被某个数整除…除这些简单的以外还有着很多比较复杂的状态构建,数位DP的核心思想还是不会变的。



三、模板

#include<bits/stdc++.h>
#define LL long long
using namespace std
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值