Beautiful numbers CodeForces - 55D(数位dp)

题目

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).
Examples
Input

1
1 9

Output

9

Input

1
12 15
Output
2

题意

寻找l到r区间上的美丽数个数,美丽数的定义为其每一位数的值都可以整除该数,则该数为美丽数。

思路

美丽数可以转化为:该数能被 ,组成其的每一位数的最小公倍数整除。设该数为y,有n位数(n<= 19),个位为x1, 百位为x2,以此类推,则所有xi的最小公倍数设为lcm,美丽数的条件转化为y%lcm = 0。
利用数位dp,dp[pos][sum][lcm]代表第pos位,前pos位组成的数为sum,组成的最小公倍数为lcm情况下,满足美丽数条件的数组个数。
因为sum很大,而其实1到9的最小公倍数为2520,所以我们对sum不断取余数2520,不影响是否能整除的结果。另外,所有位数的最小公倍数lcm其实没有2520个,hash存一下(符合是1~9中某些数字组合后的最小公倍数给个不同cont,区分开就好,cont值的大小多少比较并无意义)。
dfs到某一出口代表某一个具体的数,如果该数sum%对应的lcm为0则贡献加1,不是则为0;
dp同时备忘录储存了,在当前位置没有限制时如果已知可以直接用,有限制时枚举空间变小,不等于之前存储的dp,dp存储的都是没有限制状态下的值,在样本大时,没有限制的情况出现的次数要远远大于出现限制的情况。

扫描二维码关注公众号,回复: 8569157 查看本文章
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
ll dp[20][2521][50];
int hash[2521];
int dig[20];
int gcd(int a, int b){
	return b == 0 ? a:gcd(b, a%b);
}
int LCM(int a, int b){
	if(a == 0||b == 0)
		return a+b;
	return a*b/ gcd(a, b);
}
ll dfs(int pos, int sum, int lcm, int limit){
	if(pos == -1) return sum%lcm == 0?1:0;
	if(!limit && dp[pos][sum][hash[lcm]] != -1) return dp[pos][sum][hash[lcm]];
	int up = limit ? dig[pos]:9;
	ll ans = 0;
	int nsum = 0; int nlcm = 0;
	for(int i = 0; i <= up; i++){
		nsum = (sum*10+i)%2520;
		nlcm = LCM(i, lcm);
		ans += dfs(pos-1,nsum, nlcm, limit && i == up);
	}
	if(!limit) dp[pos][sum][hash[lcm]] = ans;
	return ans;
}
ll slove(ll x){
	int pos = 0;
	while(x){
		dig[pos++] = x%10;
		x /= 10;
	}
	ll ans = dfs(pos-1, 0, 1, 1);
	return ans;
}
int main(){
	int t, i;
	scanf("%d", &t);
	memset(dp, -1, sizeof(dp));
	int cont = 0;
	for(i = 1; i*i < 2520; i++){
		if(2520 % i == 0){
			hash[i] = cont++;
			hash[2520/i] = cont++;
		}
	}
	ll r,l;
	while(t--){
		scanf("%I64d %I64d", &l, &r);
		printf("%I64d\n", slove(r) - slove(l-1));
	}
	return 0;
}
发布了52 篇原创文章 · 获赞 2 · 访问量 864

猜你喜欢

转载自blog.csdn.net/qq_44714572/article/details/103206308