这里要求数的值整除以所有位的值,除 0 以外,所以也就很容易想到,这个数一定是要整除这些位数的最小公倍数,而这些数范围是 1∼9 ,所以最小公倍数最大也就是 2520,记录数对 2520 的余数即可,并且这里由于公倍数的数量很少,不超过五十个,所以先离散化一下优化优化,剩下的就是典型的数位 dp了。
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const ll MOD = 2520;
const int MAXN = 22;
const int MAXM = 55;
ll x, y;
int dig[MAXN];
int _hash[MOD + 10];
ll dp[MAXN][MAXM][MOD + 10];
ll gcd(ll x, ll y)
{
if (y == 0)
{
return x;
}
else
{
return gcd(y, x % y);
}
}
void init()
{
memset(dp, -1, sizeof(dp));
int cnt = 0;
for (int i = 1; i <= MOD; i++)
{
if (MOD % i == 0)
{
cnt++;
_hash[i] = cnt;
}
}
}
ll dfs(ll n, ll tag = 1, ll lcm = 1, ll num = 0)
{
if (n <= 0)
{
return num % lcm == 0;
}
if (!tag && dp[n][_hash[lcm]][num] != -1)
{
return dp[n][_hash[lcm]][num];
}
ll ans = 0;
int end = (tag == 1) ? dig[n] : 9;
for (int i = 0; i <= end; i++)
{
ll lcm_tmp;
int m = (num * 10 + i) % MOD;
if (i != 0)
{
lcm_tmp = lcm / gcd(lcm, i) * i;
}
else
{
lcm_tmp = lcm;
}
ans += dfs(n - 1, tag & (i == end), lcm_tmp, m);
}
if (!tag)
{
dp[n][_hash[lcm]][num] = ans;
}
return ans;
}
ll solve(ll x)
{
int cnt = 0;
memset(dig, 0, sizeof(dig));
while (x)
{
cnt++;
dig[cnt] = x % 10;
x /= 10;
}
ll r = dfs(cnt);
return r;
}
int main()
{
init();
int T;
scanf("%d", &T);
while (T--)
{
scanf("%lld%lld", &x, &y);
printf("%lld\n", solve(y) - solve(x - 1));
}
return 0;
}