【专题】数位DP(按位DP)

(转自http://blog.csdn.net/cmonkey_cfj/article/details/7798809)

数位DP
•在给定区间 [A,B] 内,找满足要求的数。
要求一般和数大小无关,而与数的组成有关
例如,递增的, 1234,2579…
          双峰的, 19280,26193…
         49 的, 49, 149, 1492… 
          整除 13 的, 26, 39…
麻烦在于,规模大,位数 >100 ,不能枚举。
区间往往不是整百整千,边界问题
注意
    – 记忆化搜索思路清晰
    – 开适当空间(能省则省)
    – 寻找合适的状态,简化计算量

hdu3886

题目大意:给一定区间 [A,B] ,一串由 /,\,- 组成的符号串。求满足符号串的数字个数。
/ 表示数字从左到右递增
\ 表示数字从左到右递减
- 表示数字从左到右相等
例如 :
/-\
1221,123455543
数据规模 :
A,B<=10^100

分析

F(A,B) = F(B,0)-F(A-1,0)

暴力+存储 记忆化搜索

暴力:
暴力枚举每一位 (0..9), 注意区间边界 ; 与符号的匹配。
dfs ( i,j,k,flag )
枚举第 i 位的数,匹配 str [j], 前一位是 k ,是否达到上限 (flag= true,false )
达到了上限则只能枚举 0..num[ i ] ,否则可以枚举 0..9
存储
dfs ( i,j,k,flag )
设状态与递归参数一致 f[ i ][j][k][flag] ,表示当枚举到第 i 位的数,匹配 str [j], 前一位是 k ,是否达到上限 (flag= true,false ) 时,满足要求的数字个数。
dfs 的过程,相当于在填充 f f 的空间 O(100*10*10*2) ,则 dfs 的时间 O(20000)

实现

1. 空间优化,只需记录 flag=false 时的值。因为 flag=true 的值只会计算一次,不是冗余计算,不用记录。
(不一定要开和参数一样的数组,适当变换下,分成几种情况开多个数组,可以节省下内存)
2. 前导 0 不算数,不能和符号串匹配。
,-/,0003(X),0113
3.1234  匹配 // ,会被算成俩个
4.  个位放在 f[0][…] ,且只记录 flag=false 的值时, f 与数 A,B 无关!可以反复利用

其他类型

整除 13
dfs ( i , m,flag)
枚举第 i 位数,前面枚举出的数模 13 的余数 m ,是否到达上限 flag
整除自身各位数 CF55D
dfs ( i , m,l, flag)
枚举第 i 位数,前面枚举出的数模 LCM(0..9) LCM( 前面枚举出的数 ) ,是否达到上限
包含 ”49”
dfs ( i , k,find, flag)
枚举第 i 位数,前一位是 k ,是否已包含 ”49”(find) ,是否达到上限
分类讨论: 前一 位是否为 4 ,当前是否已包含“ 49

部分解题报告:(习惯写在代码末尾...)

POJ 3252 Round Number
HDU 3709 Balanced Number
HDU 3652 B-number
codeforce 55D Beautiful numbers


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值