数位dp基础

数位动态规划是一类特殊的动态规划,它的形式一般为:给定下界$l$和上界$r$,求$[l,r]$之间满足某一要求的元素个数。

一般来说,数位动态规划有一个特定的状态表达:$f[pos][stats][bound]$

它表示:

  • 我们现在处理到了数的第pos位。在数位dp中,一般从数的高位到低位,一位一位的处理下去。例如当 $l = 13$,上界 $r = 678$的时候,我们会将上下界的高位补零使得它们有相同的位数,既$(l,r)= (013,678)$。随后从高位开始进行dp。
  • 在$pos$位之前的哪些数的状态被压缩成了$stats$。举个简单的例子,假设我们要求出$[l,r]$之间各位数字之和是$5$的倍数的数的个数,那么此时$stats$就可以表示为“在pos位之前那些数的数字之和为mod 5 的值”,这样我们只有一位就可以表示$pos$位之前的状态。如果在第${pos}$位我们选择了数d,那么动态规划中的下一个状态就为${f}[pos+1][(stats+mod) mod 5][...]$
  • 在$pos$位之前的那些数字和$l,r$的关系为$bound$。继续举例子,假如要求出[013, 678]之间各位数字之和是5的倍数的数的个数:

    1.如果最高位的数字我们选择了 2,它和上下界的最高位数字没有任何关系,因此对于次高位的数字,我们可以在 [0, 9]之间任意选择;

    2.如果最高位的数字我们选择了 6,此时这个数字是「贴着」上界的,也就是说,对于次高位的数字,我们只能在 [0, 7] 之间选择,其中 7 就是上界的次高位的数字。如果我们选择了数字 8 或 9,那么整个数为 68_,无论最后一位怎么选择,都不可能在上下界的区间内;

    3.如果最高位的数字我们选择了 0,此时这个数字是「贴着」下界的,也就是说,对于次高位的数字,我们只能在 [1, 9]之间选择,其中 1 就是下界的次高位数字。如果我们选择了数字 0,那么整个数为 00_,无论最后一位怎么选择,都不可能在上下界的区间内;

    4.此外,还有一种最为特殊的情况。如果上下界为$ (l, r) = (123, 156)$,并且最高位我们选择了 1,那么此时这个数字既「贴着」上界,也「贴着」下界,对于次高位的数字,我们只能在 [2, 5]之间选择,其中 2 是下界的次高位数字,5 是上界的次高位数字。

  综上所述,$bound$共有4中不同的取值情况,分别为0,1,2,3:

  • 如果和上下界没有任何关系,那么取值为 0,并且以后也不可能和上下界有关系;
  • 如果「贴着」下界,那么取值为 1,并且只有当第$pos$ 位取了下界对应位置的数字时,才会延续 1 值,否则会变为 0;
  • 如果「贴着」上界,那么取值为 2,并且只有当第 $pos$ 位取了上界对应位置的数字时,才会延续 2 值,否则会变为 0;
  • 如果同时「贴着」上下界,那么取值为 3,并且:如果 $pos$ 位同时取了上下界对应位置的数字(此时上下界对应位置的数字一定相同),那么延续 3值;如果$ pos $位取了下界对应位置的数字,那么会变为 1;如果$ pos$ 位取了上界对应位置的数字,那么会变为 2;其余情况会变为 0。

  而对于$ f[pos][stats][bound]$ 的值本身,它表示「满足上述条件的数的个数」。这样以来,我们可以使用记忆化搜索(DFS + memo)的方法进行动态规划即:$f[pos][stats][bound] = \sum_{d} f[pos+1][g_{s}(stats,d)][g_{b}(bound,d)]$。

  其中$d$为第$pos$位选择的数字;$g_{b}(bound,d)$是关于bound的转移函数,例如上文中0,1,2,3之间的转化;$g_{s}(stats,d)$是关于${stats}$的转移函数。最终答案存放在$f[0][stats_{init}][3]$中,即满足「枚举到最高位、初始状态、同时贴着上下界(可以想象成更高位还可以补零,那么在最高位之前的数字都是贴着上下界的)」的数的个数,也就是需要求出的答案。

 

你可能感兴趣的:(数位dp基础)