a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits.
问一个区间内[l,r]有多少个Beautiful数字
范围9*10^18
一个数字要被它的所有非零位整除,即被他们的LCM整除,可以存已有数字的Mask,但更好的方法是存它们的LCM{git[i]}
int MOD = LCM{1,2,9} = 5 * 7 * 8 * 9 = 2520
10以内的数字情况为2^3 , 3^2 , 5 , 7
所以最小公倍数组合的情况只有4*3*2*2 = 48
所以复杂度大概为19*2520*48*10(状态数*决策数)
View Code
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> using namespace std; #define LL __int64 const int Mod = 2520; LL dp[19][2520][48]; int git[2522]; int num[19]; int gcd(int a,int b) { int mod; while(b) { mod = a % b; a = b; b = mod; } return a; } int Lcm(int a,int b) { return a * b / gcd(a,b); } void init() { int num = 0; for(int i = 1; i <= Mod; i++) { if(Mod % i == 0) git[i] = num++; } memset(dp,-1,sizeof(dp)); } LL dfs(int dep,int Sum,int preLcm,bool doing) { //doing记录是否满,即是否可以从0到9枚举 if(dep == -1) return Sum % preLcm == 0; if(!doing && dp[dep][Sum][git[preLcm]] != -1) //doing为满的时候可以存起来当成公共的状态使用,降低复杂度 return dp[dep][Sum][git[preLcm]]; int end = doing? num[dep]:9; LL ans = 0; for(int i = 0; i <= end; i++) { int nowSum = (Sum * 10 + i) % Mod; int nowLcm = preLcm; if(i) nowLcm = Lcm(nowLcm,i); ans += dfs(dep - 1, nowSum, nowLcm, doing && end == i); } if(!doing)//记录一般情况,不要记录特殊情况 dp[dep][Sum][git[preLcm]] = ans; return ans; } LL cal(LL x) { int i = 0; while(x) { num[i++] = x % 10; x /= 10; } return dfs(i-1,0,1,1); } int main() { int T; scanf("%d",&T); init(); while(T--) { LL l, r; cin >> l >> r; cout << cal(r) - cal(l-1) << endl; } return 0; }