codefroces 55D Beautiful numbers

[Description]

美丽数是指能被它的每一位非0的数字整除的正整数。


[Input]

包含若干组数据,每组数据一行两个数n,m,表示求[n,m]之间的美丽数的个数。


[output]

对于每组数据输出一个答案,各占一行。

Input
1
1 9
Output
9
Input
1
12 15
Output
2

[Hit]

0 < n , m < 10^18

测试数据不超过100

 

 

 

基本思路是用:dp[len][mod][lcm]表示<=len的长度中,此数为mod,各数位的最小公倍数为lcm的数的个数来进行记忆化搜索。方法和上一题类似。

 

但我们发现,len[1,20]范围内,mod[1,1^18]范围内,lcm[1,2520]范围内。所以dp数组肯定超内存。

 

下面我们来进行内存优化:

 

假设这个数为a,各个数位的值分别为ai,那么我们发现lcm(ai) | a.

 

[1,9]的最小公倍数是2520.那么lcm(ai) | 2520, 所以lcm(ai) | (a%2520).

 

所以第二维大小我们可以从1^18降到2520,方法是%2520.

 

现在的dp数组的内存是20*2520*2520,还是很大。

 

然后我们再考虑:

 

我们发现某一个数的各个数位的数的最小公倍数最大是2520,而且只能是2520的公约数。而2520的公约数有48个。所以第三维我们只用[50]的空间就行了。

 

方法是用Hash进行离散化。‘

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long lol;
 7 int bit[21],ha[2520],len,cnt;
 8 lol f[21][2521][51],ans;
 9 int gcd(int x,int y)
10 {
11     if (!y) return x;
12     return gcd(y,x%y);
13 }
14 int lcm(int x,int y)
15 {
16     return x*y/gcd(x,y);
17 }
18 void has(int x,int l)
19 {
20     if (x>10) return;
21     if (ha[l]==0) 
22     ha[l]=++cnt; 
23     has(x+1,lcm(l,x));
24     has(x+1,l);
25 }
26 lol dfs(int pos,int pre_num,int pre_lcm,bool flag)
27 {int nxt_num,nxt_lcm,r,i;
28   lol s=0;
29     if (pos==0) 
30     return pre_num%pre_lcm==0;
31     if (flag&&f[pos][pre_num][ha[pre_lcm]]!=-1)
32     return f[pos][pre_num][ha[pre_lcm]];
33     if (flag) r=9;
34     else r=bit[pos];
35     for (i=0;i<=r;i++)
36     {
37         nxt_num=pre_num*10+i;
38         nxt_num%=2520;
39         if (i)
40         nxt_lcm=lcm(pre_lcm,i);
41         else nxt_lcm=pre_lcm;
42         s+=dfs(pos-1,nxt_num,nxt_lcm,flag||(i<r));
43     }
44     if (flag)
45     f[pos][pre_num][ha[pre_lcm]]=s;
46     return s;
47 }
48 lol solve(lol x)
49 {
50     len=0;
51     while (x)
52     {
53         len++;
54         bit[len]=x%10;
55         x/=10;
56     }
57     return dfs(len,0,1,0);
58 }
59 int main()
60 {lol l,r;
61 int T;
62     cin>>T;
63     has(2,1);
64     memset(f,-1,sizeof(f));
65     while (T--)
66     {
67         scanf("%I64d%I64d",&l,&r);
68         ans=solve(r)-solve(l-1);
69     printf("%I64d\n",ans);
70     }
71 }

 

 

 

 

posted @ 2017-09-02 19:17  Z-Y-Y-S  阅读(252)  评论(0编辑  收藏  举报