题目链接:https://cn.vjudge.net/problem/CodeForces-55D#author=0
题意:有多少数,满足是每一位数的倍数
题解:1-9的最小公倍数为2520,1-9最小公倍数的形成的种数48种,所以对于每个形成的lcm需要重新编号一下
dp[ i ][ j ][ k ] 表示还剩 i位,前面的余数是j,lcm是k的数目
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[22][2522][55], f[2522];
int w[22], len;
int getlcm(int x, int y) {
if(!y) return x;
return x * y / __gcd(x, y);
}
ll dfs(int pos, int limit, int pre, int lcm) {
if(pos < 0) return pre % lcm == 0;
if(!limit && dp[pos][pre][f[lcm]] != -1) return dp[pos][pre][f[lcm]];
int up = limit ? w[pos] : 9;
ll res = 0;
for(int i = 0; i <= up; i++) {
res += dfs(pos - 1, limit && i == up, (pre * 10 + i) % 2520, getlcm(lcm, i));
}
if(!limit) dp[pos][pre][f[lcm]] = res;
return res;
}
ll solve(ll x) {
len = 0;
while(x) {
w[len++] = x % 10;
x /= 10;
}
return dfs(len - 1, 1, 0, 1);
}
int main() {
ll l, r = 1;
for(int i = 1; i <= 10; i++) {
r = getlcm(i, r);
}
// 2520
l = 0;
int x;
// 48
for(int i = 1; i < 1024; i++) {
r = 1;
x = i;
for(int j = 1; x && j < 10; j++, x >>= 1)
if(x & 1)
r = getlcm(r, j);
if(!f[r]) f[r] = ++l;
}
memset(dp, -1, sizeof(dp));
int T;
scanf("%d", &T);
while(T--) {
scanf("%I64d %I64d", &l, &r);
printf("%I64d\n", solve(r) - solve(l - 1));
}
return 0;
}