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\n",cal(m)-cal(n-1));

54     }

55 }
View Code

 

 

 

你可能感兴趣的:(number)