跟 Nachia DP 博客学DP-16 数位 DP



需要对于给定的 $N$ 位以下的全体非负整数 $x$ 进行计算、计数等问题时候,使用这样的状态转移和设计会比较好,所以被称作 数位DP。

常见的有两种:

  1. $dp[n][c]:=$ (将 $x$ 的高位第 $n$ 位确定下来,针对这部分与特定值关系或其他由状态 $c$ 能表示的子问题的解)
  2. $dp[n][c]:=$ (将 $x$ 的低位第 $n$ 位确定下来,针对这部分与特定值关系或其他由状态 $c$ 能表示的子问题的解)

后者在某些领域也被称为 竹DP,前者是通常的数位 DP,下文我称其为 逆向数位 DP。


例题


例 1: No.741 AscNumber 不下降数字 2.0$

https://yukicoder.me/problems/no/741

EASY:逆向数位 DP 模板。

讲解见: https://sistinefibel-2006.github.io/post/20260831%20-mei-ri-%202.0%202.5%204.0.html


例 2:https://atcoder.jp/contests/dp/tasks/dp_s

https://atcoder.jp/contests/dp/tasks/dp_s

Note

给定大正整数 $K \le 10^{10000}$,找到所有比他小的正整数的数量,取模 $10^9+7$,满足:

  • 十进制表示下各个数位之和是 $D \in [1,100]$ 的倍数

如果朴素的思考,肯定会想要套用上面的模板,于是设:

$dp[n][c]:=$ 从左到右枚举到第 $n$ 位,前 $n$ 位总和是 $c$ 的数的数量

但是仔细想一想就会发现,这个设计有一些问题。少考虑了两件事情:

于是有最终的 DP 设计:$dp[n][c][0/1]:=$ 从左到右枚举到第 $n$ 位,前 $n$ 位之和取模 $D$ 为 $c$,之后还有没有可能超过 $K$ 的数字总数。

现在考虑转移设计:

考虑什么情况下有可能超过 $K$?

反之则不可能大于。

于是我们有转移方程
$$
j \in [0, 9] : dp[x][c + j \mod{D}][1] = dp[x - 1][c + j \mod{D}][1] + dp[x - 1][c + j \mod{D}][0] \cdot [j < K_{x - 1}]
$$

$$ j \in[0, 9] : dp[x][c + j \mod{D}][0] = dp[x - 1][c + j \mod{D}][0] \cdot [j = K_{x - 1}] $$

这样就行了么?

还得把 0 减去,所以 $ans - 1$ 就可以了