【CF55D】Beautiful numbers
题面
题解
考虑到如果一个数整除所有数那么可以整除他们的(lcm),而如果数(x)满足(xmod Lcm(1,2...,9)=r),且(rmod Lcm{x有的数}=0),那么这个数一定满足条件。
因为(Lcm(1,2...,9)=2520)比较小,所以我们可以存下来。
考虑数位dp,我们设(f[i][lcm][r])表示目前(dp)到第(i)位,当前已选的数的(lcm)为(lcm),前面几位(mod 2520)为(r)的数的个数。
因为(lcm)实际上最多(48)个,那么我们将这(48)个数离散一下,(dp)数组的空间就开得下了,再按照普通数位(dp)的思路转移一下就可以了。
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int Mod = 2520;
long long L, R;
int num[20], cnt, mp[2521], tot;
int Lcm(int x, int y) { return y ? x * y / __gcd(x, y) : x; }
long long f[20][50][2520];
long long Dp(int x, int lcm, int r, bool op) {
if (!x) return r % lcm ? 0 : 1;
if (!op && f[x][mp[lcm]][r] != -1) return f[x][mp[lcm]][r];
int mx = op ? num[x] : 9;
long long res = 0;
for (int i = 0; i <= mx; i++)
res += Dp(x - 1, Lcm(lcm, i), (r * 10 + i) % Mod, op & (i == mx));
if (!op) f[x][mp[lcm]][r] = res;
return res;
}
long long solve(long long pos) {
cnt = 0;
while (pos) num[++cnt] = pos % 10, pos /= 10;
num[cnt + 1] = 0;
return Dp(cnt + 1, 1, 0, 1);
}
int main () {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
#endif
memset(f, -1, sizeof(f));
for (int i = 1; i <= Mod; i++) if (Mod % i == 0) mp[i] = ++tot;
int T; cin >> T;
while (T--) {
cin >> L >> R;
cout << solve(R) - solve(L - 1) << endl;
}
return 0;
}