Codeforces #55D (数位dp+离散化)

Description

Volodya is an odd boy and his taste is strange as well. It seems to him that a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits. We will not argue with this and just count the quantity of beautiful numbers in given ranges.

Input

The first line of the input contains the number of cases t (1 ≤ t ≤ 10). Each of the next t lines contains two natural numbers li and ri (1 ≤ li ≤ ri ≤ 9 ·1018).

Please, do not use %lld specificator to read or write 64-bit integers in C++. It is preffered to use cin (also you may use %I64d).

Output

Output should contain t numbers — answers to the queries, one number per line — quantities of beautiful numbers in given intervals (from li to ri, inclusively).

Sample Input

Input

11 9

Output

9

Input

112 15

Output

2

让你找[l,r]区间中,能被自己各个非零数位整除的数的个数。一看就是满足区间减法。现在就讨论怎么求就行了。首先lcm(1..9)=2520, int MOD=2520;保存每一个数是不现实的,所以我们就.保存x%MOD就行了。preSum表示已经讨论的前面的几个数位的值(前串),preLcm表示前穿的Lcm。这里注意到1...9的各种lcm可以离散化处理,只有48个,这样可以大大减少数组的空间。我们再用flag来表示当前位的数字大小是否超过x对应位的大小例:x=15666;当我们讨论到千位是1,2,3,4时,后面三位是随便选的,讨论千位是5是,百位就不能随便选了,要<=6,此时在千位我们就达到了边界。剩下的交给dfs。PS:有人把2520优化成252的,92ms过了...我1122ms...代码如下:
 1 #include <bits/stdc++.h>
 2
 3 using namespace std;
 4
 5 const int MAXN=25;
 6 const int MOD=2520;
 7 long long dp[MAXN][MOD][48];
 8 int index[MOD+10],bit[MAXN];//index表示1..9的各种组合lcm,bit是将数字的每一位拆开保存
 9 long long int gcd (long long int a,long long int b) {return (b==0)?a:gcd(b,a%b);}
10 long long int lcm (long long int a,long long int b){return a/gcd(a,b)*b;}
11 void init()//来找1...9之间各种组合的lcm
12 {
13     int num=0;
14     for (int i=1;i<=MOD;++i)
15     if (MOD%i==0)
16     index[i]=num++;
17 }
18 long long dfs (int pos,int preSum,int preLcm,bool flag)//pos当前位,flag前面几位是否达到边界
19 {
20     if (pos==-1)//讨论到最后一位
21     return preSum%preLcm==0;//如果这个数满足要求,+1
22     if (!flag && dp[pos][preSum][index[preLcm]]!=-1)//没达到边界而且访问过这个状态
23     return dp[pos][preSum][index[preLcm]];//直接return,记忆化搜索
24     long long ans=0;
25     int endd=flag?bit[pos]:9;//这位达到边界时,下一位从0到x的对应位变化。没达到边界是0...9变化
26     for (int i=0;i<=endd;i++)
27     {
28         int nowSum=(preSum*10+i)%MOD;//添加下一位数字,然后更新状态
29         int nowLcm=preLcm;
30         if (i)
31         nowLcm=lcm(nowLcm,i);
32         ans+=dfs(pos-1,nowSum,nowLcm,flag&&i==endd);
33     }
34     if (!flag)
35     dp[pos][preSum][index[preLcm]]=ans;
36     return ans;
37 }
38 long long calc (long long x)
39 {
40     memset(bit,0,sizeof bit);
41     int pos=0;
42     while (x)
43     {
44         bit[pos++]=x%10;
45         x/=10;
46     }
47     return dfs(pos-1,0,1,1);
48 }
49 int main()
50 {
51     int t;
52     long long int l,r;
53     init();
54     memset(dp,-1,sizeof dp);
55     scanf("%d",&t);
56     while (t--)
57     {
58         scanf("%I64d%I64d",&l,&r);
59         printf("%I64d\n",calc(r)-calc(l-1));
60     }
61     return 0;
62 }
 
时间: 2024-12-03 05:33:50

Codeforces #55D (数位dp+离散化)的相关文章

Codeforces 55D (数位DP+离散化+数论)

题目链接: http://poj.org/problem?id=2117 题目大意:统计一个范围内数的个数,要求该数能被各位上的数整除.范围2^64. 解题思路: 一开始SB地开了10维数组记录情况. 首先要求能被各位上的数整除,可以转化为被一个数整除问题. 这个数就是各位上数的最小公倍数LCM(不是GCD). 其次,处理整除问题,得转化成数位DP的余数模板.1~9的LCM最大是2520, 那么%2520,让其可以开数组进行记忆化搜索. 最后, 对于不能%2520最后结果,再%各个数位累计过来的

Codeforces 13C Sequence --DP+离散化

题意:给出一个 n (1 <= n <= 5000)个数的序列 .每个操作可以把 n 个数中的某一个加1 或 减 1.问使这个序列变成非递减的操作数最少是多少 解法:定义dp[i][j]为将前i个数变为以j为结尾的非递减序列的最少操作次数. 则有: dp[i][j] = min(dp[i][j], min(dp[i][k]) + Cost(原来第i个位置上的数转换到j))  (1 <= k <= j) 即前i个数以j结尾的状态可以由前i-1个数以小于等于j的k结尾的状态转移过来,取

CodeForces 55D Beautiful numbers(数位dp&amp;&amp;离散化)

题目链接:[kuangbin带你飞]专题十五 数位DP A - Beautiful numbers 题意 ps:第一道数位dp,题真好,虽然是参考大牛方法悟过才a,但仍收获不少. 求一个区间内的Beautiful numbers有多少个.Beautiful numbers指:一个数能整除所有组成它的非0数字. 例如15可以被1和5整除,所以15是Beautiful numbers. 思路 Beautiful numbers指:一个数能整除所有组成它的非0数字. 等同于 一个数能整除 所有组成它的

codeforces 215E 数位DP

题意:一个数的二进制表示如果是一个周期数那么它就是需要的,问[l,r]中有多少个好的数 题解:明显很像数位DP,枚举第一周期的长度,根据第一周期的数值大小来确定有多少种方案,注意首位不能为0.然后就是要注意去重问题,因为对于第一周期长度为k算到的数字,长度为k可以整除的数时必定也算过一遍,减一下就好了,根据这个去重 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<stri

Codeforces 628D 数位dp

题意:d magic number(0<=d<9)的意思就是一个数,从最高位开始奇数位不是d,偶数位是d 题目问,给a,b,m,d(a<=b,m<2000)问,a,b之间有多少个数满足既是d magic number,又可以被m整除 a,b的范围很大,都是2000位,且a,b的位数一样,这一点很重要 分析:这题一看又有取模,又是大整数,那肯定是要用数位dp做, 通常的数位dp,我们要解决(0,x)的区间中的答案,但是这个题不需要, 注意刚才我说过一点,a,b是位数相同的整数,假设s

Find a car CodeForces - 809C (数位DP)

大意: 给定一个$1e9\times 1e9$的矩阵$a$, $a_{i,j}$为它正上方和正左方未出现过的最小数, 每个询问求一个矩形内的和. 可以发现$a_{i,j}=(i-1)\oplus (j-1)+1$, 暴力数位$dp$即可 #include <iostream> #include <sstream> #include <algorithm> #include <cstdio> #include <cmath> #include &l

CodeForces 55D - Beautiful numbers - [数位DP+离散化]

题目链接:https://cn.vjudge.net/problem/CodeForces-55D Volodya is an odd boy and his taste is strange as well. It seems to him that a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits. We will not argue with

cf 55D 数位dp 好题

/* 刚开始我考虑0的情况,想将他剔除就将lcmn设为-1,这样还要判断0和lcmn是-1的情况很麻烦而且但是一直出错 后来觉得不用管0的情况就行了,可以认为符合. 解:将lcmn离散化,因为1-9的公倍数必是2520的因子并且只有48个 所以用一个数组离散化,记忆的时候直接调用离散数组即可 因为一个数的所有数字的最小公倍数必定是2520的因子,所以将这个数对2520取余缩小范围并记忆 三维,第一个长度,第二个对2520取余,第三个是lcm值 */ #include<stdio.h> #inc

Codeforces 55D. Beautiful numbers(数位DP,离散化)

Codeforces 55D. Beautiful numbers 题意 求[L,R]区间内有多少个数满足:该数能被其每一位数字都整除(如12,24,15等). 思路 一开始以为是数位DP的水题,觉得只需要记录搜到当前位出现了哪些数字作为状态即可,明显是假算法...感觉这是一道数位DP好题.可以这样思考:一个数要想被其各位数字分别都整除,等价于它被那些数字的LCM整除.因此记录当前位,当前数对(1~9的LCM)取模的结果,当前出现的数字的LCM这三个值作为状态才合理,即dp[pos][sum][