CF 55D Beautiful numbers 数位DP

思路:

要找一个数能被他的所有反的数字整除,只需求出这个数能被其数字的LCM整除。而LCM最大为5*7*8*9=2520;

如果直接开dp[20][2520][2520]会超内存,而2^3,3^2,5,7的组合只有4*3*2*2=48种,所以开dp[20][2520][50]即可。

链接:http://codeforces.com/problemset/problem/55/D

代码如下:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define ll __int64
 5 using namespace std;
 6 int bit[20],hash[2529];
 7 ll dp[20][2521][50];
 8 int gcd(int a,int b)
 9 {
10     if(a<b) swap(a,b);
11     while(b){
12         int t=a;
13         a=b;
14         b=t%b;
15     }
16     return a;
17 }
18 ll dfs(int pos,int num,int lcm,bool f)
19 {
20     if(pos==-1) return num%lcm==0;
21     if(!f&&dp[pos][num][hash[lcm]]!=-1) return dp[pos][num][hash[lcm]];
22     ll ans=0;
23     int e=f?bit[pos]:9;
24     for(int i=0;i<=e;i++){
25         int g=lcm;
26         if(i>=2) g=g/gcd(g,i)*i;
27         ans+=dfs(pos-1,(num*10+i)%2520,g,f&&(i==bit[pos]));
28     }
29     if(!f) dp[pos][num][hash[lcm]]=ans;
30     return ans;
31 }
32 ll cal(ll n)
33 {
34     int m=0;
35     while(n){
36         bit[m++]=n%10;
37         n/=10;
38     }
39     return dfs(m-1,0,1,1);
40 }
41 int main()
42 {
43     ll n,m;
44     int t,i,j;
45     memset(dp,-1,sizeof(dp));
46     for(j=0,i=1;i<=2520;i++){
47         if(2520%i==0)
48             hash[i]=j++;
49     }
50     scanf("%d",&t);
51     while(t--){
52         scanf("%I64d%I64d",&n,&m);
53         printf("%I64d
",cal(m)-cal(n-1));
54     }
55 }
View Code
原文地址:https://www.cnblogs.com/xin-hua/p/3304245.html