【总结】数位 DP
记号约定
我们用 \(A=\overline{(a_{n-1} a_{n-2} a_{n-3} \cdots a_{0})_B}\) 表示一个 \(n\) 位 \(B\) 进制数(大多数情况下 \(B=10\) 或 \(B=2\) )。
- 即: \(A=\overline{(a_{n-1} a_{n-2} a_{n-3} \cdots a_{0})_B}=\sum_{i\in[0,n)} a_i B^i\)
令集合 \(S_B=\{\overline{(a_{n-1} a_{n-2} a_{n-3} \cdots a_{0})_B}|n\in[1,\infty)\cap Z,a_i\in[0,B]\cap Z\}\) 为所有 \(B\) 进制数构成的集合
问题刻画
抽象地来说,一般来说数位 \(\text{DP}\) 要解决的问题都可以转化成下面形式的问题:
定义函数 \(P:S_B\to \{1,0\}\) ,求函数 \(f([l,r])=\sum_{x\in S_B\cap [l,r]} P(x)\) 。
Acwing 1082. 数字游戏
题目描述
科协里最近很流行数字游戏。
某人命名了一种不降数,这种数字必须满足从左到右各位数字呈非下降关系,如 \(123,446\)。
现在大家决定玩一个游戏,指定一个整数闭区间 \([a,b]\),问这个区间内有多少个不降数。
\(1\le a\le b<2^{31}\)
技巧 1 : \(f([l,r])\to S(r) - S(l-1)\)
令 \(S(i)=\sum_{k\in[st,i]} f([st,k])\) 。
若 \(l,r \ge st\) ,那么一定有 \(f([l,r])= S(r) - S(l-1)\) 。
那么我们可以将问题转化为:
- 有多少整数 \(v \le \overline{a_{n-1} a_{n-2} a_{n-3} \cdots a_{0}}\) 满足从左到右各位数字呈非下降关系。
技巧 2 : 数位统计的基本集合划分
我们转化的问题为有多少整数 \(v \le \overline{a_{n-1} a_{n-2} a_{n-3} \cdots a_{0}}\) 满足从左到右各位数字呈非下降关系。
对于该问题最棘手的限制其实是对 \(v\) 大小限制(上界)的限制。
为了方便思考我们将所有不带前补 \(0\) 的 \(k < n\) 位 \(B\) 进制数补成带前补 \(0\) 的 \(n\) 位 \(B\) 进制数。
考虑两个带前补 \(0\) 的 \(n\) 位 \(10\) 进制整数:
\(A=\overline{a_{n-1} a_{n-2} a_{n-3} \cdots a_{0}}\)
\(B=\overline{b_{n-1} b_{n-2} b_{n-3} \cdots b_{0}}\)
其中 \(B < A\) 。
考虑一个位置 \(k\) ,满足 \(\forall i> k,a_i=b_i,a_k>b_k\) 。
一个直观的标记:
\(A=\overline{a_{n-1} \cdots {\color{red}a_{k}} \cdots a_{0}}\)
\(B=\overline{b_{n-1} \cdots {\color{red}b_{k}} \cdots b_{0}}\)
关于这个位置 \(k\) 有两个显然但十分重要的性质:
-
对于任意 \(B<A\) 一定存在位置 \(k\) 。
-
对于任一 \(k\) 不同的两个数 \(B,C\) 一定有 \(B\not= C\) 。
那么我们就可以将 \(k\) 作为集合划分的依据,枚举 \(k=k_i\) 时的数的个数。
接下来考虑对于 \(k=k_i\) 时的集合划分情况:
我们考虑 \(k_i\) 位的取值,因为已经第 \(k_i\) 位一定比 \(A\) 小,所以剩下的 \(k_i\) 位可以随便填数。
那么接下来要解决的问题即:
- 有多少 \(m\) 位十进制数满足 \(A= \overline{a_{m-1} a_{m-2} a_{m-3} \cdots a_{0}}\) 满足从左到右各位数字呈非下降关系。
而对于这个问题我们可以用一个十分简单的 \(\text{DP}\) 解决。