定义了一种 数。不含前导零且相邻两个数字之差至少为 的正整数被称为 数。 想知道, 在 和 之间,包括 和 ,总共有多少个 数?
首先是套路,将 转化为 。
反正我觉得我用记忆化搜索解数位DP十分顺溜,这回我就还是用记忆化搜索解这道题。
我们用 表示处理到第 位,当前最高位是 的方案数。
由于数字的特殊性,在 是还要加两个 。分别表示是否是最高位(排除前导 ),以及当前的数是否和那个上限重合(听起来有点抽象。举个例子就是给定一个数 。当前枚举第三位是 的话,第二位就是 ~ 之间任意一个数,而第三位是 的话,第二位只能取 ~ )有了状态转移就很方便了。直接把所有可能的都加上即可。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
int d[20][10], bits[20];
int dfs(int pos, int pre, bool limit, bool first) {
if (pos == 0) return 1;
if (!limit && !first && d[pos][pre] != -1) return d[pos][pre];
int u = limit ? bits[pos] : 9, ret = 0;
for (int i = 0; i <= u; i++) {
if (first || (!first && abs(pre - i) >= 2))
ret += dfs(pos - 1, i, limit && i == u, first && !i);
}
return limit || first ? ret : d[pos][pre] = ret;
}
int calc(int n) {
memset(d, -1, sizeof d);
int len = 0;
while (n) {
bits[++len] = n % 10;
n /= 10;
}
return dfs(len, 0, true, true);
}
int main() {
int a, b;
scanf("%d%d", &a, &b);
std::cout << calc(b) - calc(a - 1) << std::endl;
return 0;
}