题目链接:【codeforces 55D】
美丽的数x:x能整除它本身的非零的数字
问l~r之间的美丽的数的个数(1<=l<=r<=9*10^18)
1~9的最小公倍数是2520,从左往右搜,每次记录mod2520后的余数,到目前数字为止的最小公倍数(要用has离散化,否则会超内存)
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
#define ll __int64
#define mod 2520
ll dp[20][3000][50], l, r;
int t, arr[20], has[3000];
void init()
{
memset(dp, -1, sizeof(dp));
int cnt = 0;
for(int i=1; i<=2520; i++)
{
if(mod%i==0)
{
has[i] = ++cnt;
}
}
}
int gcd(int a, int b)
{
int ret = 1;
while(ret)
{
ret = a%b;
a = b;
b = ret;
}
return a;
}
int lcm(int a, int b)
{
return a/gcd(a, b)*b;
}
ll dfs(int pos, int premod, int prelcm, int lim)
{
if(!pos) return premod%prelcm==0;
if(!lim && dp[pos][premod][has[prelcm]]!=-1)
return dp[pos][premod][has[prelcm]];
int end = lim?arr[pos]:9;
ll ans=0;
for(int i=0; i<=end; i++)
{
int nextmod = (premod*10+i)%mod;
int nextlcm = prelcm;
if(i) nextlcm = lcm(prelcm, i);
ans += dfs(pos-1, nextmod, nextlcm, lim&&i==end);
}
if(!lim) dp[pos][premod][has[prelcm]] = ans;
return ans;
}
ll solve(ll x)
{
int len=0;
while(x)
{
arr[++len] = x%10;
x/=10;
}
return dfs(len, 0, 1, 1);
}
int main()
{
init();
scanf("%d", &t);
while(t--)
{
scanf("%I64d%I64d", &l, &r);
printf("%I64d\n", solve(r)-solve(l-1));
}
return 0;
}