题目描述
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.
输入
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 should contain t numbers — answers to the queries, one number per line — quantities of beautiful numbers in given intervals (from li to ri, inclusively).
样例
样例输入一
1
1 9
样例输出一
9
样例输入二
1
12 15
样例输出二
2
分析
一句话题意:有T组询问,每次询问区间[l, r]中的beautiful number有多少。beautiful number是指这个数可以被组成它的数字整除。例如15是beautiful number,因为15可以被1整除,也可以被5整除。25不是beautiful number, 25不能被2整除。
这道题数据范围达到了9e18,如果暴力枚举的话一定会T掉
所以我们要借助一个神奇的东西-——数位DP
0x00 前置知识:数位DP
引用自StungYep的博客
数位dp(Digit Entry DP)是一种计数用的dp,一般就是要哦统计区间[l,r]内满足一些条件的数的个数。所谓数位dp,字面意思就是在数位上进行dp。数位的含义:一个数有个位、十位、百位、千位......数的每一位就是数位啦!
数位dp的实质就是换一种暴力枚举的方式,使得新的枚举方式满足dp的性质,然后记忆化就可以了。
模板
1 typedef long long ll; 2 int a[20]; 3 ll dp[20][state]; //不同题目状态不同 4 ll dfs(int pos,int state,bool lead,bool limit) //变量,状态,前导0,数位上界;注意不是每题都要判断前导零 5 { 6 if(pos==0) return 1; //递归边界,一般一种递归到结束只能产生一种情况 7 if(!limit && !lead && dp[pos][state]!=-1) return dp[pos][state]; //记忆化 8 int up=limit?a[pos]:9; //枚举上界 9 ll ans=0; //计数 10 for(int i=0;i<=up;i++) //枚举,然后把不同情况的个数加到ans就可以了 11 { 12 if() ... 13 else if()... //一下条件 14 ans+=dfs(pos-1,/*状态转移*/,lead && i==0,limit && i==a[pos]) //最后两个变量传参都是这样写的 15 //state状态转移要保证i的合法性,比如不能有62,那么当pre==6&&i==2就不合法,这里用state记录pre是否为6即可。 16 } 17 if(!limit && !lead) dp[pos][state]=ans; 18 return ans; 19 } 20 ll solve(ll x) 21 { 22 int tot=0; 23 while(x) 24 { 25 a[++tot]=x%10; 26 x/=10; 27 } 28 return dfs(tot/*从最高位开始枚举*/,/*一系列状态 */,true,true);//刚开始最高位都是有限制并且有前导零的,显然比最高位还要高的一位视为0嘛 29 } 30 int main() 31 { 32 ll le,ri; 33 while(~scanf("%lld%lld",&le,&ri)) 34 { 35 //初始化dp数组为-1,这里还有更加优美的优化,后面讲 36 printf("%lld\n",solve(ri)-solve(le-1)); 37 } 38 }