题目思路:数位dp,若这个数能被每位的非0数整除,那么这个数一定可以被每一位数的lcm整除,lcm(1,2,3,4,5,6,7,8,9) = 2520,所以可以通过将这个数对2520取模来压缩空间,取模结果计做mod
dp[pos][lcm][mod],显然20*2520*2520仍然过大,所以我们对mod进行离散,再次压缩空间。
#include <iostream> #include <cmath> #include <string.h> #include <cstdio> #include <queue> #include <algorithm> using namespace std; #define LL long long #define MAXSIZE 2600 #define INF 0x3f3f3f3f LL dp[20][50][MAXSIZE]; const LL Mod = 2520; int bit[MAXSIZE],ha[MAXSIZE]; LL gcd(LL n,LL m) { if(n%m == 0) return m; return gcd(m,n%m); } void Init() { int pos = 1; for(int i=1;i<=Mod;i++) { if(2520%i == 0) ha[i] = pos++; } } LL dfs(int pos,int lcm,int mod,int limit) { if(pos < 0) { if(mod%lcm == 0) return 1; return 0; } if(dp[pos][ha[lcm]][mod] != -1 && !limit) return dp[pos][ha[lcm]][mod]; LL ans = 0; int len = limit?bit[pos]:9; for(int i=0;i<=len;i++) { if(i != 0) { int new_lcm = lcm*i/(gcd(lcm,i)); int num = (mod*10+i)%Mod; ans += dfs(pos-1,new_lcm,num,limit&&i==len); } else { int num = mod*10%Mod; ans += dfs(pos-1,lcm,num,limit&&i==len); } } if(!limit) dp[pos][ha[lcm]][mod] = ans; return ans; } LL Solve(LL n) { int pos = 0; while(n) { bit[pos++] = n%10; n /= 10; } LL ans = dfs(pos-1,1,0,1); return ans; } int main() { Init(); int T; LL n,m; scanf("%d",&T); memset(dp,-1,sizeof(dp)); while(T--) { scanf("%lld%lld",&n,&m); LL ans = Solve(m) - Solve(n-1); printf("%lld ",ans); } return 0; }