【題目來源】
https://www.acwing.com/problem/content/3713/
【題目描述】
給定兩個整數 l,r(l≤r),請問 [l, r] 範圍內,滿足數字的任意相鄰兩位差值都恰好為 1,且數字至少有兩位的數有多少個。

【輸入格式】
第一行包含整數 T,表示共有 T 組測試數據。
每組數據佔一行,包含兩個整數 l 和 r。

【輸出格式】
每組數據輸出一行,一個結果。

【輸入樣例】
14 2023

【輸出樣例】
1
17

【數據範圍】
1≤T≤100,
0≤l≤r≤3×10^8

【算法分析】
● 從最高位到最低位枚舉,最高位有 1~9 共 9 種選擇(最高位不能為 0)。其後的每一位,因為要滿足“任意相鄰兩位差值都恰好為 1”的約束條件,所以,最高位之後的每一位的值,只有兩種選擇。鑑於題目給出的最大數為 3×10^8,故總的選擇數為 9×2^8=2304。

● 也就是説,從最高位到最低位枚舉求解,不會超時(TLE)。

● 下面代碼中,函數 dfs 的各個形參含義:u表示當前數的位數,x表示當前數的值,pre記錄上一位數的值

【算法代碼:】

#include <bits/stdc++.h>
using namespace std;

int le,ri,cnt;
int T;

//u表示當前數的位數,x表示當前數的值,pre記錄上一位數的值
void dfs(int u,int x,int pre) {
    if(x>ri) return;
    if(u>1 && x>=le && x<=ri) cnt++;

    if(u==0) {
        for(int i=1; i<10; i++) dfs(u+1,x*10+i,i);
    } else {
        if(pre) dfs(u+1,x*10+pre-1,pre-1);
        if(pre<9) dfs(u+1,x*10+pre+1,pre+1);
    }
}

int main() {
    cin>>T;
    while(T--) {
        cnt=0;
        cin>>le>>ri;
        dfs(0,0,-1);
        cout<<cnt<<endl;
    }
    return 0;
}

/*
in:
4
1 10
10 10
1 100
0 300000000

out:
1
1
17
1992
*/

【算法代碼:數位DP】→ 

#include <bits/stdc++.h>
using namespace std;

const int N=12;
int f[N][10]; //f[i][j]表示長度為i最高位為j的滿足條件的數字個數

void init() {
    for(int i=0; i<=9; i++) f[1][i]=1;
    for(int i=2; i<N; i++) {
        for(int j=0; j<=9; j++) {
            if(j==0) f[i][j]=f[i-1][1];
            else if(j==9) f[i][j]=f[i-1][8];
            else f[i][j]=f[i-1][j-1]+f[i-1][j+1];
        }
    }
}

int dp(int n) {
    if(n<=0) return 0; //vip
    vector<int> v;
    while(n) {
        v.push_back(n%10);
        n/=10;
    }

    int cnt=0,pre=-1;
    for(int i=v.size()-1; v.size()>=2 && i>=0; i--) {
        int x=v[i];
        int start=(i==v.size()-1)?1:0;
        for(int j=start; j<x; j++) {
            if(pre==-1 || abs(pre-j)==1) {
                cnt+=f[i+1][j];
            }
        }

        if(abs(pre-x)==1 || pre==-1) pre=x;
        else break;

        if(i==0) cnt++;
    }

    for(int i=2; i<=v.size()-1; i++) {
        for(int j=1; j<=9; j++) cnt+=f[i][j];
    }
    return cnt;
}

int main() {
    init();
    int T,le,ri;
    cin>>T;
    while(T--) {
        cin>>le>>ri;
        cout<<dp(ri)-dp(le-1)<<endl;
    }
}

/*
in:
4
1 10
10 10
1 100
0 300000000

out:
1
1
17
1992
*/