CF55D Beautiful numbers

CF55D Beautiful numbers

题目描述

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.

Volodya 是个奇怪的男孩,他的品味也很奇怪。 在他看来,当且仅当正整数可以被其每个非零数字整除时,它才是 Beautiful 的。 我们不会对此争论,而只计算给定范围内的 Beautiful number 的数量。

输入格式

The first line of the input contains the number of cases t(1 ≤ t ≤ 10)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).

输入的第一行包含数据组数t (1 ≤ t ≤ 10), 接下来的t行中的每行包含两个自然数 \(l_i\)\(r_i(1 \le l_i \le r_i \le 9 \times 10 ^ {18})\).

请不要使用 %lld 在 C++ 中读取或写入 \(64\) 位整数。 建议使用 cin (也可以使用 %l64d ) .

输出格式

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

\(t\) 行,每行输出从 \(l_i\)\(r_i\) 的 Beautiful number 的数量

思路

设状态 \(d[i][j][k][l]\),其中 \(i\) 表示当前数位 , \(j\) 表示模 \(\text{lcm}(1\sim 9) = 2520\) 的余数 , \(k\) 表示当前与上界的关系(\(1\) 代表等于,\(0\) 代表小于) , \(l\) 表示 \(1\sim 9\) 在数位中出现的情况。

注意 \(\text {lcm}\) 需要预先处理, \(2520\) 的因子也进行预处理并离散化,\(l\)\(\text {lcm}\) 编号表示。

状态转移方程为:

\[p=d[i+1][(j\times 10+x)\bmod 2520][k\ \text{and}\ x = top][id[\mathrm {lcm}(id[x], l)]]\\ p\gets p+d[i][j][k][l]; \]

其中 \(x\) 为当前枚举的数位,\(top\) 是当前位的上界,\(id\)\(2520\) 因子的离散化数组。

代码

#include<bits/stdc++.h>
#define ULL long long 
using namespace std;
const int mod = 2520;
int id[3000];
ULL d[30][3000][2][50], LCM[50][50];
ULL fac[50] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 18, 20, 21, 24, 28, 30, 35, 36, 40, 42, 45, 56, 60, 63, 70, 72, 84, 90, 105, 120, 126, 140, 168, 180, 210, 252, 280, 315, 360, 420, 504, 630, 840, 1260, 2520};
ULL gcd(ULL x, ULL y){
	if(!y) return x;
	return gcd(y, x % y);
}
ULL lcm(ULL x, ULL y){
	return x / gcd(x, y) * y;
}
ULL Getans(ULL num){
	if(!num) return 1ll;
	memset(d, 0, sizeof(d));
	int a[30], b[30];
	int cnt = 0;
	while(num){
		b[++cnt] = num % 10;
		num /= 10;
	}
	for(int i = 1; i <= cnt; i++) a[i] = b[cnt-i+1];
	ULL ans = 0;
	d[0][0][1][1] = 1;
	for(int i = 0; i < cnt; i++)
		for(int j = 0; j < mod; j++)
			for(int k = 0; k <= 1; k++)
				for(int l = 1; l <= 48; l++)
					if(d[i][j][k][l]){
						int top = k ? a[i+1] : 9;
						for(int x = 0; x <= top; x++){
							d[i+1][(j*10+x)%mod][k && x == top][x ? id[LCM[l][id[x]]] : l] += d[i][j][k][l];
						}
					}
	for(int j = 1; j <= 48; j++){
		for(int i = 0; i < mod; i+=fac[j]){
			if(!(i % fac[j]))
				ans += d[cnt][i][1][j] + d[cnt][i][0][j];
		}
	}
	return ans;
}
inline ULL read(void){
	ULL num = 0, f = 1;
	char ch;
	while(!isdigit(ch=getchar())) if(ch == '-') f = -1;
	while(isdigit(ch)) num = num*10 + ch-'0', ch = getchar();
	return num * f;
}
int main()
{
	for(int i = 1; i <= 48; i++) id[fac[i]] = i;
	for(int i = 1; i <= 48; i++)
		for(int j = 1; j <= 48; j++)
			LCM[j][i] = LCM[i][j] = lcm(fac[i], fac[j]);
	int T = read();
	while(T--){
		ULL l = read(), r = read();
		printf("%lld\n", Getans(r) - Getans(l-1));
	}
	return 0;
}
posted @ 2020-07-31 14:10  Michmh  阅读(141)  评论(0)    收藏  举报