艰难的数位DP

数位DP 看起来感觉是很高端大气上档次的东东 可惜在两位师傅的指导下,我貌似还是不算太会,所以我下定决心好好学习数位DP,那么我先从水题HDOJ 2089开始

简单介绍下数位DP:

以【1, 56724】区间为例。

第一位必须是0-4的情况下才会满足后四位是任意的数字;同理第二位必须是0-5的情况下彩绘满足后三位是任意的数字;以此类推下去。。。

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

暴力+存储 记忆化搜索

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


7k大神数位DP模版:                                                  

int dfs(int i, int s, bool e) {
    if (i==-1) return s==target_s;
    if (!e && ~f[i][s]) return f[i][s];
    int res = 0;
    int u = e?num[i]:9;
    for (int d = first?1:0; d <= u; ++d)
        res += dfs(i-1, new_s(s, d), e&&d==u);
    return e?res:f[i][s]=res;
}

其中:

f为记忆化数组;

i为当前处理串的第i位(权重表示法,也即后面剩下i+1位待填数);

s为之前数字的状态(如果要求后面的数满足什么状态,也可以再记一个目标状态t之类,for的时候枚举下t);

e表示之前的数是否是上界的前缀(即后面的数能否任意填)。

for循环枚举数字时,要注意是否能枚举0,以及0对于状态的影响,有的题目前导0和中间的0是等价的,但有的不是,对于后者可以在dfs时再加一个状态变量z,表示前面是否全部是前导0,也可以看是否是首位,然后外面统计时候枚举一下位数。It depends.

!e==true 表示后面的数,不可以为任意的数。 ~f[ i ][ s ] => f[ i ][ s ] != -1 记忆化搜索  同时满足俩个条件则返回f[ i ][ s ];

当e为false时表示后面的数位可以为任意的数 故此后面的位可以枚举从0-9。 反之亦然, 当e==true时代表后面的数位不可以为任意的数 后面的位只可以枚举从0-num[ i ]。

HDOJ 2089

给一段范围【a, b】 求出其中不包含64或4的数的个数。


未完待续。。。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值