[CF55D]Beautiful numbers

本文介绍了一种使用数位动态规划(DP)解决区间内特定数学性质数的数量问题的方法。具体针对的是,找出在给定区间内,能够被其每位数字整除的数的个数。通过构建DP状态表示到当前位数下,前几位数模2520(LCM(1,2,...,9))的值,实现了高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:多次询问,询问区间$[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;
}

  

转载于:https://www.cnblogs.com/Memory-of-winter/p/9780187.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值