CodeForces 55D Beautiful numbers
题目链接:http://codeforces.com/problemset/problem/55/D
题意:一个数如果能够被她的每一个非0位整除,那么这个数就叫做Beautiful numbers。
给出l和r,问区间[l,r]中总共有多少个Beautiful numbers。
思路:
题意即这个数要能够被它的每个非0位的最小公倍数整除。
因为每一位最多就是1,2,3,4,5,6,7,8,9。也就是这个数最坏的情况要能够被1*2*3*4*5*6*7*8*9 = 2520整除。
设这个数为x,设x = 2520*t+y。设lcm为x每个非0位出现的数的最小公倍数。
那么可以知道2520 % lcm = 0。
所以x % lcm = x%2520%lcm。所以在记忆化搜索的时候只要保存当前数%2520的余数就可以了。
所以需要一个dp[cur][last][lcm] 大小有19*2520*2520要超内存,所以要把记录的lcm离散化一下。
1 #include <bits/stdc++.h> 2 using namespace std; 3 long long l, r; 4 int num[22]; 5 int Hash[2550]; 6 long long dp[22][2530][50]; 7 void init() 8 { 9 memset(dp, -1, sizeof(dp)); 10 int cnt = 0; 11 Hash[0] = 0; 12 for(int i = 1; i <= 2520; i++) 13 { 14 if(2520%i == 0) Hash[i] = ++cnt; 15 } 16 } 17 18 int gcd(int a, int b) 19 { 20 if(a < b) return gcd(b, a); 21 if(b == 0) return a; 22 return gcd(b, a%b); 23 } 24 int getlcm(int a, int b) 25 { 26 return a/gcd(a,b)*b; 27 } 28 long long dfs(int cur, int last, int lcm, int limit) 29 { 30 if(cur < 0) 31 { 32 if(last % lcm == 0) return 1; 33 else return 0; 34 } 35 if(!limit && dp[cur][last][Hash[lcm]] != -1) return dp[cur][last][Hash[lcm]]; 36 37 long long ret = 0; 38 int up = limit?num[cur]:9; 39 for(int i = 0; i <= up; i++) 40 { 41 int temp = (last*10+i)%2520; 42 int nowlcm; 43 if(i != 0) nowlcm = getlcm(lcm, i); 44 else nowlcm = lcm; 45 ret += dfs(cur-1, temp, nowlcm, limit && i == up); 46 } 47 if(!limit) dp[cur][last][Hash[lcm]] = ret; 48 return ret; 49 } 50 long long slove(long long x) 51 { 52 int cnt = 0; 53 while(x) 54 { 55 num[cnt++] = x % 10; 56 x /= 10; 57 } 58 return dfs(cnt-1, 0, 1, 1); 59 } 60 int T; 61 int main() 62 { 63 init(); 64 scanf("%d", &T); 65 while(T--) 66 { 67 cin>>l>>r; 68 cout<<slove(r) - slove(l-1)<<endl; 69 } 70 return 0; 71 }