codeforces55D_数位dp

题目链接

参考链接:http://blog.csdn.net/to_be_better/article/details/50658392

题意:

求一个区间内的Beautiful numbers有多少个。Beautiful numbers指:一个数能整除所有组成它的非0数字。 
例如15可以被1和5整除,所以15是Beautiful numbers。

思路

Beautiful numbers指:一个数能整除所有组成它的非0数字。 
等同于 一个数能整除 所有组成它的非0数字的最小公倍数。 
我们看到数据的范围是1 ≤ li ≤ ri ≤ 9 ·1018,根本无法记录。 
所以,缩小范围成为第一要做的事。 
先看一个小式子。

    sum%(x*n)%x == sum%x;

证明:设sum = k*x+b
    等号左边:
        sum%(x*n)%x -> (k*x+b)%(x*n)%x 
        将k转为ka*n + kb代入;
        (ka*n*x+kb*x+b)%(x*n)%x -> (kb*x+b)%x -> b%x -> b
    等号右边:
        b
左右相等,证明成立
那么我们就可以用上式中的x*n对num进行取余,记录其取余后的值,显然,19的最小公倍数2520是最合理的x*n。 
而在逐位统计时,可以直接由前面位取余后的值来得到包含新一位的新数字取余后的值。 
例如 RX(R是已知前面位取余后的值),那么Rx%2520 == (R*10+x)%2520。就不在此废话证了。 
我们使用记忆化搜索。 
**dfs(len, num, lcm, flag) 
len表示迭代的长度, 
num为截止当前位的数对2520取余后的值。 
lcm为截止当前位的所有数的最小公倍数。 
flag表示当前数是否可以任意取值(对取值上限进行判断)** 
则可用dp[len][num][lcm]来对其进行记录。 
但lcm2520取值根本开不下,所以对lcm进行离散化,因为lcm一定可以整除2520,所以将12520可以整除2520的数进行标记即可,测试后发现只有48个,满足当前情况。
复制代码
 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <vector>
 7 #include <ctime>
 8 #include <queue>
 9 #include <list>
10 #include <set>
11 #include <map>
12 using namespace std;
13 #define INF 0x3f3f3f3f
14 typedef long long LL;
15 
16 LL dp[20][50][2550];
17 int fact[2550], bit[20];
18 void find()
19 {
20     memset(fact, 0, sizeof(fact));
21     int cnt = 0;
22     for(int i = 1;  i <= 2520; i++)
23         if(2520 % i == 0)
24             fact[i] = cnt++;
25 }
26 LL dfs(int len, int lcm, int mod, int flag)
27 {
28     LL sum = 0;
29     if(len == 0)
30         return mod % lcm == 0;
31     if(flag && dp[len][fact[lcm]][mod] >= 0)
32         return dp[len][fact[lcm]][mod];    
33     int te = flag ? 9 : bit[len];
34     for(int i = 0; i <= te; i++)
35     {
36         int Lcm = lcm;
37         if(i != 0){
38             int x = __gcd(lcm, i);
39             Lcm = lcm * i / x;
40         }
41         int Mod = (i + mod * 10) % 2520;
42         sum += dfs(len - 1, Lcm, Mod, flag || i < te);
43     }
44     if(flag)
45         dp[len][fact[lcm]][mod] = sum;
46     return sum;
47 }
48 LL solve(LL n)
49 {
50     int len = 0;
51     while(n)
52     {
53         bit[++len] = n % 10;
54         n /= 10;
55     }
56     return dfs(len, 1, 0, 0);
57 }
58 int main()
59 {
60     int t;
61     find();
62     LL l, r;
63     scanf("%d", &t);
64     memset(dp, -1, sizeof(dp));
65     while(t--)
66     {
67         scanf("%I64d %I64d", &l ,&r);
68         printf("%I64d\n", solve(r) - solve(l - 1));
69     }
70     return 0;
71 }
View Code
复制代码

 

 
posted @   海无泪  阅读(156)  评论(0编辑  收藏  举报
编辑推荐:
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
阅读排行:
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥
点击右上角即可分享
微信分享提示