题目传送门

#include <bits/stdc++.h>

using namespace std;
const int N = 15;
int a[N];
int dp[N][N];

/**
 *
 * @param pos   当前位置
 * @param pre   前一位数位的数字是多少
 * @param lead  本位是不是需要考虑前导0
 * @param limit 是否贴着上界
 * @return
 */
int dfs(int pos, int pre, bool lead, bool limit) {
    if (pos == -1) return 1;
    if (!limit && !lead && ~dp[pos][pre]) return dp[pos][pre];//注意模板变化
    int res = 0, up = limit ? a[pos] : 9;
    for (int i = 0; i <= up; i++)
        if (abs(pre - i) >= 2) { //这里根据题意变化
            bool st = lead && !i;
            /*
              如果此位置还在要求考虑前导0,表示之前就没有出现过非0数字,并且本位置填充的依然是0
              那么
              (1)lead = st 下一数位依然要保持警惕,小心前导0,否则就可以放心大胆的不理这个概念了~
              (2)pre = -2

              如果不上面的情况,那么 pre直接记录i即可。
            */
            res += dfs(pos - 1, st ? -2 : i, st, limit && i == up);
        }
    return limit ? res : dp[pos][pre] = res;
}

int cal(int x) {
    memset(dp, -1, sizeof dp);
    int pos = 0;
    while (x) a[pos++] = x % 10, x /= 10;
    //pre 给初值-2,保证首位是啥都可以
    //lead:true 表示第一位也需要考虑是不是前导零,第一位就是0,也不可以
    //limit:true : 表示贴上界,不能大于当前的a[pos-1]这一位
    return dfs(pos - 1, -2, true, true);
}

int main() {
    int l, r;
    cin >> l >> r;
    cout << cal(r) - cal(l - 1) << endl;
    return 0;
}

相关文章: