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

 

你可能感兴趣的:(codeforces)