题意:
数字满足的条件是该数字可以被它的每一位非零位整除。

思路:

数位dp的核心思路就是找到判断这个数的满足条件的方法,这个题的条件就是这个数要能被自己的每一个非零位整除,也就是应该被每一非零位的最小公倍数整除,而的最小公倍数是,现在就可以拟确定dfs的参数和dp的状态了。

表示当前处理到第位,表示当前数值的值,表示当前的最小公倍数,表示当前是否有范围限制。

临界点也是最重要的部分,当时,返回

数位dp的状态就应该是,即位数符合条件的数的个数,但最大都是,也就是说数位要开,开不了这么大。但一维里面的很多空间是多余的,因为的最小公倍数有种,所以将离散化到的区间,这样就可以开的数组了。

MyCode:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 607,mod=2520;
inline ll read() {
    ll s = 0, w = 1;
    char ch = getchar();
    while (ch < 48 || ch > 57) {
        if (ch == '-') w = -1;
        ch = getchar();
    }
    while (ch >= 48 && ch <= 57)
        s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s * w;
}
ll dis[49]={0,1,2,3,4,5,6,7,8,9,10,12,14,15,18,20,21,24,28,30,35,36,40,42,45,56,60,63,70,72,84,90,105,120,
126,140,168,180,210,252,280,315,360,420,504,630,840,1260,2520};
int mp[2521];
ll dp[21][2521][49],inf[21];
int digit[20];
int gcd(int a,int b) {
    return b==0?a:gcd(b,a%b);
}
ll dfs(int len,int sum,int lcm,bool limit) {
    if(!len) return sum%lcm==0;
    int tmp=mp[lcm];
    ll ans=0;
    if(!limit&&dp[len][sum][tmp]!=-1) return dp[len][sum][tmp];
    int endi=(limit?digit[len]:9);
    ans+=dfs(len-1,sum,lcm,limit&&0==endi);
    for(int i=1;i<=endi;++i)
        ans+=dfs(len-1,(sum+i*inf[len])%mod,lcm/gcd(lcm,i)*i,limit&&i==endi);
    if(!limit) dp[len][sum][tmp]=ans;
    return ans;
}
ll solve(ll x) {
    int len=0;
    while(x) {
        digit[++len]=x%10;
        x/=10;
    }
    return dfs(len,0,1,true);
}
int main() {
    for(int i=1;i<=48;++i) mp[dis[i]]=i;
    inf[1]=1;
    for(int i=2;i<=19;++i) inf[i]=inf[i-1]*10%mod;
    memset(dp,-1,sizeof dp);
    int t=read();
    while(t--) {
        ll l=read(),r=read();
        printf("%I64d\n",solve(r)-solve(l-1));
    }
    return 0;
}