真是好数啊:)

#include<iostream>
#include<cstring>
using namespace std;
using ll=long long;
ll dp[20][11];
//预处理出两数间是否符合倍数关系
int flag[11][11];
int g[20];
void init(){
    for(int i=0;i<10;++i){
        dp[1][i]=1;
    }
    for(int i=2;i<=19;++i){
        for(int j=0;j<10;++j){//首位0还是需要的,因为后面的dp需要它
            for(int k=0;k<10;++k){
                if(flag[j][k]==1)//成倍数关系,才累加
                    dp[i][j]+=dp[i-1][k];
            }
        }
    }

}
ll solve(ll n){
    int len=0;
    ll ans=0;
    memset(g,0,sizeof(g));
    while(n){
        g[++len]=n%10;
        n/=10;
    }
    for(int i=1;i<=len-1;++i){
        for(int j=1;j<=9;++j){
            ans+=dp[i][j];
        }
    }
    for(int i=1;i<g[len];i++){
        ans+=dp[len][i];
    }
    for(int i=len-1;i>0;--i){
        for(int j=0;j<g[i];++j){
            if(flag[g[i+1]][j]==1){//高位与当前位满足倍数关系
                ans+=dp[i][j];
            }
        }
        if(flag[g[i+1]][g[i]]==0)//当前位已经不满足了,及时退出
            break;//这一步是必要的!!因为我这个循环只考虑当前位与上一位是否符合
    }
    return ans;
}
int main(){
    int n;
    cin>>n;
    ll l,r;
    for(int i=0;i<10;++i){
        for(int j=0;j<10;++j){
            if(i==0||j==0||i%j==0||j%i==0){
                flag[i][j]=1;
            }
           
        }
    }
    init();
    while(n--){
        cin>>l>>r;
        ll ans=solve(r+1)-solve(l);
        if(l==0)
            cout<<ans+1<<endl;
        else
            cout<<ans<<endl;
    }
}