如果一个数能够被组成它的各个非0数字整除,则称它是完美数。例如:1-9都是完美数,10,11,12,101都是完美数,但是13就不是完美数(因为13不能被数字3整除)。
现在给定正整数x,y,求x和y之间(包含x和y的闭区间)共有多少完美数。
Input
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 10000) 第2 - T + 1行:每行2个数,X, Y中间用空格分割。(1 <= X <= Y <= 10^18)
Output
输出共T行,对应区间中完美数的数量。
Input示例
2 1 9 12 15
Output示例
9 2
思路:
能整除每个数位的数意味着能整除这些数位的最小公倍数。1-9的最小公倍数为2520。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
const int MOD = 2520;
int a[MAXN], Lcm[MAXN];
ll dp[20][3000][50];
void init()
{
int tot = 0;
for (int i = 1; i <= 2520; i++)
{
if (2520 % i == 0)
{
Lcm[i] = ++tot;
}
}
}
int gcd(int a, int b)
{
if (a % b == 0)
{
return b;
}
else
{
return gcd(b, a % b);
}
}
int getlcm(ll x,ll y)
{
return (x * y) / gcd(x, y);
}
ll dfs(int pos, int p, int lcm, bool limit)
{
if (pos == -1)
{
return p % lcm == 0;
}
if (!limit && dp[pos][p][Lcm[lcm]] != -1)
{
return dp[pos][p][Lcm[lcm]];
}
ll result = 0;
int up = limit? a[pos] : 9;
for (int i = 0; i <= up; i++)
{
int temp = lcm;
if (i > 0)
{
temp = getlcm(temp, i);
}
result += dfs(pos - 1, (p * 10 + i) % 2520, temp, limit && i == a[pos]);
}
if (!limit)
{
dp[pos][p][Lcm[lcm]] = result;
}
return result;
}
ll solve(ll x)
{
int pos = 0;
while (x)
{
a[pos] = x % 10;
x /= 10;
pos++;
}
return dfs(pos - 1, 0, 1, true);
}
int main()
{
int t;
scanf("%d", &t);
init();
memset(dp, -1, sizeof(dp));
while (t--)
{
ll l,r;
scanf("%lld%lld", &l, &r);
printf("%lld\n", solve(r) - solve(l - 1));
}
return 0;
}