若一个数n能被它的所有非零数位整除,则n能被它们的最小公倍数x整除
而由1到9中的数组成的最小公倍数最大为2520,且是离散的,实际上只有48个
为了判断这个数能否被它的所有数位整除,我们还需要这个数的值,显然要记录值是不可能的,其实我们只需记录它对2520的模即可
设dp[pos][lcm][mod]表示当前位为pos,前面那些数位的最小公倍数为lcm,前面那些位对2520的模为mod,在用一个flag表示是否达到上限,进行记忆化搜索就好啦
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define mod 2520 5 int tab[]={48,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}; 6 int hsh[2600],dig[20]; 7 ll dp[20][50][2520]; 8 void PP(){ 9 for(int i=1;i<=tab[0];i++) 10 hsh[tab[i]]=i; 11 } 12 int gcd(int a,int b){ return b?gcd(b,a%b):a; } 13 int lcm(int a,int b){ return a*b/gcd(a,b); } 14 ll dfs(int dep,int cur_lcm,int cur_yu,int flag){ 15 if(!dep)return cur_yu%tab[cur_lcm]?0:1; 16 if(!flag&&dp[dep][cur_lcm][cur_yu]!=-1)return dp[dep][cur_lcm][cur_yu]; 17 int lim=flag?dig[dep]:9; 18 ll ans=0; 19 for(int i=0;i<=lim;i++){ 20 int nxt_lcm=i?hsh[lcm(tab[cur_lcm],i)]:cur_lcm; 21 int nxt_yu=(cur_yu*10+i)%mod; 22 ans+=dfs(dep-1,nxt_lcm,nxt_yu,flag&(i==lim)); 23 } 24 if(!flag)dp[dep][cur_lcm][cur_yu]=ans; 25 return ans; 26 } 27 ll solve(ll x){ 28 int dd=0; 29 while(x)dig[++dd]=x%10,x/=10; 30 return dfs(dd,1,0,1); 31 } 32 int main(){ 33 PP(); 34 int T; 35 scanf("%d",&T); 36 memset(dp,-1,sizeof(dp)); 37 while(T--){ 38 ll A,B; 39 scanf("%lld%lld",&A,&B); 40 printf("%lld ",solve(B)-solve(A-1)); 41 } 42 return 0; 43 }