————————————————————————————————————
题目的意思是求一个区间有多少个数,数要求能被他的每一位整除
思路:数位dp,开3位数组记录长度位len的,到len为止和为sum的,sum容易很大,但可以知道1到9的最小公倍数为2520,所以可以对2520取模,LCM为lcm的书有多少个,然后dfs递归求解
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <cstdio>
#include <set>
#include <cmath>
#include <map>
#include <algorithm>
#define INF 0x3f3f3f3f
#define MAXN 10000005
#define Mod 10001
using namespace std;
#define LL long long
LL dp[20][3000][50];
int a[20],index[3000];
int mod;
int gcd(int x,int y)
{
return x%y==0?y:gcd(y,x%y);
}
int _lcm(int x,int y)
{
return x*y/gcd(x,y);
}
void init()
{
mod=1;
for(int i=1; i<10; i++)
{
mod=_lcm(mod,i);
}
int ct=0;
for(int i=1; i<=mod; i++)
{
if(mod%i==0) index[i]=ct++;
}
memset(dp,-1,sizeof dp);
}
LL dfs(int len,int sum,int lcm,bool limit)
{
if(len<0)
return sum%lcm==0;
if(dp[len][sum][index[lcm]]!=-1&&!limit)
return dp[len][sum][index[lcm]];
int up=limit?a[len]:9;
LL ans=0;
for(int i=0; i<=up; i++)
{
ans+=dfs(len-1,(sum*10+i)%mod,i?_lcm(lcm,i):lcm,limit&&i==up);
}
return limit?ans:dp[len][sum][index[lcm]]=ans;
}
LL solve(LL x)
{
int cnt=0;
while(x>0)
{
a[cnt++]=x%10;
x/=10;
}
return dfs(cnt-1,0,1,1);
}
int main()
{
int T;
LL n,m;
init();
for(scanf("%d",&T); T--;)
{
scanf("%lld%lld",&n,&m);
printf("%lld\n",solve(m)-solve(n-1));
}
return 0;
}