CodeForces 55D Beautiful numbers(数位dp+数论)

来源:互联网 发布:吉林农产品交易所 知乎 编辑:程序博客网 时间:2024/05/17 08:34

Beautiful numbers

time limit per test:4 seconds

memory limit per test:256 megabytes

input:standard input

output:standard output

Volodya is an odd boy and his taste is strange as well. It seems to him that a positive integer number isbeautiful 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 nextt lines contains two natural numbers li andri (1 ≤ li ≤ ri ≤ 9 ·1018).

Please, do not use %lld specificator to read or write 64-bit integers in C++. It is preffered to usecin (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 (fromli tori, inclusively).

Examples
Input
11 9
Output
9
Input
112 15
Output
2


         很明显的一道数位dp,但是转移却并不是那么好想。

        大致题意是,让你求区间内所有的能够每一位数字整除的数字有多少个。

        最初始的想法是,设置dp[len][x]表示长度为x时且当前为x的倍数的时候的数量,但是在考虑转移的时候却发现,不能很好的处理这个倍数整除关系,每次新加入一个数字就会产生一个新的因子。于是抛弃这个想法。这里,我们考虑利用一些同余的性质,若a≡b(mod m) 且d|m 则a≡b(mod d)。我们可以知道,lcm(1~9)=2520,若a≡b(mod 2520) 且xi|2520  则a≡b(mod xi) 。is strange 那么,所有满足%xi==0的数字一定满足%2520==0,有了一个必要条件。根据这个,我们就能够把每个数字的%2520之后的具体大小当作dp数组的参数,也即可以知道每个数字对xi取模后的数值。根据这个,再在转移的时候加上当前已经选取过的数字的lcm,就可以完成转移。

        具体来说,设dp[len][mod][lcm]表示当前长度为len,数字对2520取模之后的大小为mod,已取数字LCM为lcm时的方案数。有转移方程dp[len][mod][lcm]=Σdp[len-1][(mod*10+xi)%2520][__lcm(xi,lcm)]。按照正常数位dp的方式转移求即可。另外还要注意空间,正常来说,最后一维lcm最大也可以取到2520,但是这样19*2520*2520,即使是256M的内存也会超。但是真正的lcm并没有那么多,我们可以预先dfs出所有可能出现的lcm的数值,然后重标号即可,事实正名最多只有48个lcm的数值,一一对应即可。具体见代码:

#include <bits/stdc++.h>#define INF 0x3f3f3f3f#define LL long long#define N 1100using namespace std;int num[20],mp[2520],tot,n;LL dp[20][2520][50];LL __lcm(int x,int y)//求lcm,注意有0的情况{    if (!x||!y) return x+y;    LL gcd=__gcd(x,y);    return x*y/gcd;}LL dfs(int len,int mod,int lcm,bool lim){    if (len<=0) return mod%lcm==0;    if (!lim&&dp[len][mod][mp[lcm]]) return dp[len][mod][mp[lcm]];//记忆化搜索    LL res=0; int up=lim?num[len]:9;//判断最大限制    for(int i=0;i<=up;i++)        res+=dfs(len-1,(mod*10+i)%2520,__lcm(i,lcm),lim&&i==up);//状态转移    if (!lim) dp[len][mod][mp[lcm]]=res;    return res;}LL cal(LL x){    tot=0;    while(x)    {        num[++tot]=x%10;        x/=10;    }    return dfs(tot,0,1,1);}void getlcm(int x,int lcm)//预处理出所有的lcm可能{    if (x>9)    {        if (!mp[lcm]) mp[lcm]=++n;        return;    }    getlcm(x+1,__lcm(lcm,x));    getlcm(x+1,lcm);}int main(){    int T_T;    cin>>T_T;    getlcm(1,1);    while(T_T--)    {        LL l,r; scanf("%I64d%I64d",&l,&r);        printf("%I64d\n",cal(r)-cal(l-1));    }    return 0;}

原创粉丝点击