CodeForces 55D Beautiful numbers

数位dp中不错的题目

求能够整除自身各位数字的数,那换句话来说也就是能够整除各位数的最小公倍数,可以算出1-9所有数字的最小公倍数为2000+

从高位向下走的时候,要保留当前第几位i,当前lcm,以及前面对lcm的余数r,不过这个lcm是变换的,状态无法保存。

可以看下这个式子 x%m = x%(2*m)%m  显然,是可以的。那么就想到有没有一个lcm是所有可能出现的lcm的倍数,可以想到就是上面算出的2000+

现在就能确定函数里的几个参数了,i,lcm,MOD,r  但是这样存的话 明显数组开不了,又可以想下其实1-9中算出来的最小公倍数的数量不会有2000+这么多

1 2 3 4 5 6 7 8 9  最后为 5 7 8 9 也就是 5 7 2^3 3^2  那么总共的最小公倍数数量也就为2*2*4*3 = 48 这样就可以节省内存了。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define N 2520
12 #define LL long long
13 #define INF 0xfffffff
14 const double eps = 1e-8;
15 const double pi = acos(-1.0);
16 const double inf = ~0u>>2;
17 LL dp[22][50][N+2];
18 int d[20],p[55],o,po[N+2];
19 void init()
20 {
21     int i,g=0;
22 
23     for(i = 1; i <= N ; i++)
24     if(N%i==0)
25     po[i] = ++g;
26 
27 }
28 LL dfs(int i,bool e,int lcm,int r)
29 {
30     if(i==-1)
31     return r%lcm==0;
32     if(!e&&dp[i][po[lcm]][r]!=-1)
33     return dp[i][po[lcm]][r];
34     int j;
35     int mk = e?d[i]:9;
36     LL ans = 0;
37     for(j = 0 ;j <= mk ; j++)
38     {
39         if(j==0)
40         ans+=dfs(i-1,e&&j==mk,lcm,(r*10)%N);
41         else
42         {
43             int ll = lcm/__gcd(lcm,j)*j;
44             ans+=dfs(i-1,e&&j==mk,ll,(r*10+j)%N);
45         }
46     }
47     return e?ans:dp[i][po[lcm]][r] = ans;
48 }
49 LL cal(LL x)
50 {
51     int g = 0;
52     while(x)
53     {
54         d[g++] = x%10;
55         x/=10;
56     }
57     return dfs(g-1,1,1,0);
58 }
59 int main()
60 {
61     int t;
62     LL l,r;
63     cin>>t;
64     init();
65     memset(dp,-1,sizeof(dp));
66     while(t--)
67     {
68         cin>>l>>r;
69         cout<<cal(r)-cal(l-1)<<endl;
70     }
71     return 0;
72 }
View Code
原文地址:https://www.cnblogs.com/shangyu/p/3682966.html