【数位DP】 CF 55D Beautiful numbers

时间:2020-04-17
本文章向大家介绍【数位DP】 CF 55D Beautiful numbers,主要包括【数位DP】 CF 55D Beautiful numbers使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目大意

洛谷链接
给出一个正整数\(n\),若这个数可以被其每一位上的数整除,那么就称其为\(Beautifu\ Number\)。给出一个区间,求该区间中\(Beautiful\ Number\)的个数。

输入格式

第一行是数据组数\(t\)
每组给出\(l_i\)\(r_i\),为区间的左端点和右端点。
不要用\(\%lld\)读入长整形。建议使用\(cin\)\(\%I64d\)。(\(cin\)党的胜利吗orz)

数据范围

\(1\le t \le 10,1\le l_i\le r_i\le 9×10^{18}\)

输出格式

输出\(t\)行,每行给出每组数据的答案。

样例1输入

1
1 9

样例1输出

9

样例2输入

1
12 15

样例2输出

2

思路

前置知识

  • 一个数可以同时被几个数整除,那么这个数也可以被这几个数的最小公倍数整除。
  • 1、2、3、……、10的最小公倍数为2520。

正解

这道题正解就是数位DP(还是到黑题老姚迫害学生石锤了
首先必须有的就是一个维度储存当前的位数,还有两个维度就是数的值和每一位数的最小公倍数。
但是要存\(9×10^{18}\)显然不太现实,但是这个数其实和这个数模上\(2520\)是等效的,因此存该数模\(2520\)就可以了。
这时的数组就出来了\(DP[20][2525][2525]\),里面储存的是当前满足情况的\(Beautifu\ Number\)的个数。

一些优化

  • 数据量极大,所以将区间改为前缀形式,即\([1,r]-[1,l-1]\);
  • 直接开数组是开不下的。在1~2520中,满足是2520的因数的只有48个数字,因此第三维度的大小可以改为48(或者50稳妥一点)

部分代码

/*
MOD:MOD==2520;
now:当前所在位数;     
bevalue:now位之前的数%2520;
lcm:now位之前的数的每一位数的最小公倍数;
ismax:当前是否是已知区间内的最大值;
num[]:一个vector,储存每一位的数字;
factor[]:一个数组,储存了离散化后的2520的因数
findlcm:一个函数,求两个数的最小公倍数(应该知道怎么写吧)
*/
long long dfs(int now,int bevalue,int lcm,bool ismax){
    if(now==-1) 
        return bevalue%lcm==0;//如果已经处理完了最后一位,判断该数是否满足条件
    if(ismax==0&&dp[now][bevalue][factor[lcm]]!=-1) 
        return dp[now][bevalue][factor[lcm]];
        //如果不是最大值,并且当前情况已经计算过了(初始化都设为-1),直接返回值

    long long ans=0;
    int maxnum= (ismax==1) ? num[now] : 9; 
    //如果前几位是最大值情况,那么当前位最大值为这一位的数,否则为9

    for(int i=0;i<=maxnum;i++){//从0开始枚举
        int nxtbevalue=(bevalue*10+i)%MOD;//计算包含当前位后所需数值的值
        int nxtlcm=lcm;  
        if(i!=0){
            nxtlcm=findlcm(nxtlcm,i);
            //若当前位置不为0,计算包含当前位后所有位上的数的最小公倍数(如果为零就是原数)
        }
        ans+=dfs(now-1,nxtbevalue,nxtlcm,ismax&&i==maxnum); 
        //如果前几位是最大值的情况,而且当前位为最大值时,ismax=1
    }

    if(ismax==0){//如果不是最大值,记录结果
        dp[now][bevalue][factor[lcm]]=ans;
    }

    return ans;
}
int main(){
    ......
    dfs(num.size()-1,0,1,1)//从后往前
    ......
}

原文地址:https://www.cnblogs.com/Midoria7/p/12719853.html