数位 DP
引入
一般数位 DP 的题目是这样的:
有一个返回值为 bool 类型的函数 \(f(x)\)。这个函数一般是跟 \(x\) 的数位有关的。
给定 \(l, r\),求 \(l \sim r\) 中有多少 \(x\) 的 \(f(x)\) 为真。
\(l, r \le 10^{18}\)。
典型的例子是 windy 数:
求 \(l \sim r\) 中有多少个数,满足其不含前导零且相邻两个数字之差至少为 \(2\)。
前置
我们回顾一下如何比较两个数 \(a, b\) 的大小。
下面定义 \(g_j(i)\) 表示 \(i\) 的第 \(j\) 个十进制位(从右往左数,从 \(0\) 开始)是多少。例如 \(g_{2}(114514) = 5\)。
- \(a = 114\) 和 \(b = 99\):
- \(g_2(a) = 1\),\(g_2(b) = 0\)。所以 \(a > b\)。
- 这告诉我们位数多的数大。
- \(a = 919\),\(b = 114\):
- \(g_2(a) = 9\),\(g_2(b) = 1\)。所以 \(a > b\)。
- 这告诉我们最高位大的数大。
- \(a = 191\) 和 \(b = 114\):
- \(g_2(a) = g_2(b) = 1\),不能判断。
- \(g_1(a) = 9\),\(g_1(b) = 1\)。所以 \(a > b\)。
- 这告诉我们在最高位相同的情况下,次高位大的数大。
- \(a = 119\),\(b = 114\):
- \(g_2(a) = g_2(b) = 1\),不能判断。
- \(g_1(a) = g_1(b) = 1\),不能判断。
- \(g_0(a) = 9\),\(g_0(b) = 4\)。所以 \(a > b\)。
- 这告诉我们在最高位、次高位相同的情况下,第三高的位大的数大。
- 依次类推。
所以呢?这告诉我们这样一个事情:
- 对于数 \(a\),如果一个数 \(b\) 的最前面几位与 \(a\) 相同,接下来的一位比 \(a\) 小,那么剩下的位不管是 \(0 \sim 9\) 都能保证 \(a > b\)。
例如,在 \(a = 114514\),\(b = 113999\) 时,有这样几个关系:
- \(g_5(a) = g_5(b)\);
- \(g_4(a) = g_4(b)\);
- \(g_3(a) > g_4(b)\);
- \(g_2(b) \in [0, 9]\);
- \(g_1(b) \in [0, 9]\);
- \(g_0(b) \in [0, 9]\);
这个东西是很显然的,但很关键。
分析
回到题目。我们利用前缀和的思想,转化成求 \(f(x)\) 表示 \(1 \sim x\) 中有多少满足条件的数,也就是有多少比的小于等于 \(x\) 的数满足条件。那么答案为 \(f(r) - f(l - 1)\)。
那么问题就来到了 \(f(x)\) 上。
接下来,我们令 \(y\) 表示一个比 \(x\) 小的数,\(a_i\) 表示 \(x\) 的第 \(i\) 个十进制位,\(b_i\) 表示 \(y\) 的第 \(i\) 个十进制位,\(cnt\) 表示其位数。例如 \(x = 114514\) 时 \(a_{1 \sim 6} = \{4, 1, 5, 4, 1, 1\}\)。
上面提到,如果 \(x > y\),那么一定存在一个整数 \(k \in [1, cnt]\),使得:
- 若 \(k \le i \le cnt\),\(a_i = b_i\);
- \(a_k > b_k\);
- 若 \(1 \le i < k\),\(b_i \in [0, 9]\)。
那么这启发我们可以枚举使得 \(a_k > b_k\) 的 \(k\),然后计算答案。这样做我们就将 \(1 \sim x - 1\) 的数分成了 \(cnt\) 类。然后单独计算 \(x\) 是否合法即可。
接下来要做的事情需要根据题目分析。以 windy 数为例。
首先枚举 \(k\),再枚举 \(b_k \in [0, a_k - 1)\)。我们需要让相邻两个数字之差至少为 \(2\)。此时,我们已经知道了 \(b_{k + 1} = a_{k + 1}\),所以此时可以之间判断枚举的 \(b_k\) 是否合法,即是否满足 \(|a_{k + 1} - b_k| \ge 2\)。
如果满足,那么问题就变成了:
有多少个 \(k\) 位数,其最高位为 \(b_k\),并且满足相邻两个数字之差至少为 \(2\)。其中 \(k\) 和 \(b_k\) 是给定的。
这个可以直接预处理 DP。设 \(f_{i, j}\) 表示有多少个 \(i\) 位数的最高位为 \(j\)。那么转移:
边界 \(f_{1, i} = 1\)。