[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; }