[CF55D]Beautiful numbers

题目大意:多次询问,询问区间$[l,r]$中,能被它自己的每一位数上的数整除的数的个数

题解:数位$DP$,$dp_{i,j}$表示到了第$i$位,前几位表示的数模$2520(LCM(1,2,\dots,9))$的值为$j$的方案数

卡点:数组开小,溢出(话说快$\text{NOIP}$了,我还经常这样,是不是要挂)

C++ Code:

#include <cstdio>
#define maxn 2530
const int mod = 2520;

int Tim;
int ret[maxn], mp[maxn];
long long f[20][maxn][50];
int num[20];
int gcd(int a, int b) {
	if (!b) return a;
	else return gcd(b, a % b);
}
int __lcm(int a, int b) {
	if (!a || !b) return a | b;
	return a * b / gcd(a, b);
}
long long calc(int x, int sum, int lcm, bool lim) {
	if (!x) return (sum % ret[lcm] == 0);
	long long F = f[x][sum][lcm];
	if (!lim && ~F) return F;
	F = 0;
	for (int i = lim ? num[x] : 9, op = 1; ~i; i--, op = 0) {
		F += calc(x - 1, (sum * 10 + i) % mod, mp[__lcm(ret[lcm], i)], lim && op);
	}
	if (!lim) f[x][sum][lcm] = F;
	return F;
}
long long solve(long long x) {
	int tot = 0;
	while (x) {
		num[++tot] = x % 10;
		x /= 10;
	}
	return calc(tot, 0, 0, true);
}
int tot;
int main() {
	scanf("%d", &Tim);
	for (int i = 1; i <= 2520; i++) if (mod % i == 0) mp[i] = tot, ret[tot++] = i;
	__builtin_memset(f, -1, sizeof f);
	while (Tim --> 0) {
		long long l, r;
		scanf("%lld%lld", &l, &r);
		printf("%lld\n", solve(r) - solve(l - 1));
	}
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/Memory-of-winter/p/9780187.html