如果一个数能够被组成它的各个非0数字整除,则称它是完美数。例如:1-9都是完美数,10,11,12,101都是完美数,但是13就不是完美数(因为13不能被数字3整除)。
现在给定正整数x,y,求x和y之间(包含x和y的闭区间)共有多少完美数。
一个数能整除他的所有位上的数,也就是说要整除所有位置上的数字的lcm。
那么设f[i][j][k]表示做到第i位,模2520意义下数字为j,lcm为第k个的数字个数。2520是1-9中最大的lcm,那么预处理2520以内所有的lcm,对于相同的lcm明显可以分为一组。
然后直接记忆化搜索,枚举前一位上的数字即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e5+5;
const int mo=2520;
typedef long long ll;
int a[50],Lcm[N],num[N];
ll f[20][3000][50];
inline void pre()
{
int tot=0;
fo(i,1,2520)
if (2520%i==0)Lcm[i]=++tot;
}
inline int gcd(int a,int b)
{
if (a%b==0)return b;
else return gcd(b,a%b);
}
inline int getlcm(ll x,ll y)
{
return x*y/gcd(x,y);
}
inline ll dfs(int i,int p,int lcm,bool bz)
{
if (i==-1)return p%lcm==0;
if (!bz&&f[i][p][Lcm[lcm]]!=-1)
return f[i][p][Lcm[lcm]];
ll ans=0;
int lim=bz?num[i]:9;
fo(x,0,lim)
{
int lcm1=lcm;
if (x>0)lcm1=getlcm(lcm1,x);
ans=ans+dfs(i-1,(p*10+x)%2520,lcm1,bz&&x==lim);
}
if (bz)return ans;
else return f[i][p][Lcm[lcm]]=ans;
}
ll solve(ll x)
{
int t=0;
while(x)
{
num[t++]=x%10;
x/=10;
}
return dfs(t-1,0,1,1);
}
int main()
{
int cas;
scanf("%d",&cas);pre();
memset(f,-1,sizeof(f));
while (cas--)
{
ll x,y;
scanf("%lld%lld",&x,&y);
printf("%lld\n",solve(y)-solve(x-1));
}
}