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