题目大意:如果一个数能被组成他的各个数整除,就成这个数为美丽数字,为l~r之间有多少个美丽数字。
题目思路:S为一个数的每位数字的集合,如果一个数字能整除每位数字上的数,那么这个数字一定能整除LCM(S),S的最大值为LCM(1,2,3,4,5,6,7,8,9)=2520。
所以对于所有美丽数字n有:n%2520%LCM(s)==0
数位DP时left传递n%2520,lcm传递LCM(s)
另外dp[20][2520][2520]是会爆内存的,但是LCM一共只有不超过50种可能,所以可以压缩一下为dp[20][50][2520]
#include<iostream> #include<algorithm> #include<cstring> #include<vector> #include<stdio.h> #include<stdlib.h> #include<queue> #include<math.h> #include<map> #define INF 0x3f3f3f3f #define MAX 2525 #define Temp 1000000000 #define mod 2520 using namespace std; int num[MAX],has[MAX]; int p[MAX]={0,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}; long long dp[20][50][2525]; int GCD(int a,int b) { if(a%b==0) return b; return GCD(b,a%b); } int LCM(int a,int b) { return a*b/GCD(a,b); } long long dfs(int pos,int lcm,int left,bool limit) { if(pos<0) return lcm && left%p[lcm]==0; if(!limit && dp[pos][lcm][left]!=-1) return dp[pos][lcm][left]; long long ans=0; int len=limit?num[pos]:9; for(int i=0;i<=len;i++) { int new_left=(left*10+i)%mod; int new_lcm=lcm?has[LCM(p[lcm],max(i,1))]:max(i,0); ans+=dfs(pos-1,new_lcm,new_left,limit&&i==len); } if(!limit) dp[pos][lcm][left]=ans; return ans; } long long solve(long long k) { int len=0; while(k) { num[len++]=k%10; k/=10; } return dfs(len-1,0,0,true); } int main() { int T; long long l,r; scanf("%d",&T); for(int i=0;i<49;i++) has[p[i]]=i; memset(dp,-1,sizeof(dp)); while(T--) { scanf("%lld%lld",&l,&r); long long ans1=solve(l-1); long long ans2=solve(r); long long ans=ans2-ans1; printf("%lld ",ans); } return 0; }