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
一个数整除所有位置上的数,也就是整除这些数的lcm,最多2520。然后记录每一个数对2520的余数,数位dp。另外,lcm的数量不是很多,离散化记录。
代码:
//#pragma comment(linker, "/STACK:655360000")
#pragma warning(disable:4996)
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define INF 0x333f3f3f
#define repp(i, n, m) for (int i = n; i <= m; i++)
#define rep(i, n, m) for (int i = n; i < m; i++)
#define sa(n) scanf("%d", &(n))
const ll mod = 2520;
const int maxn = 1e5 + 5;
const double PI = acos(-1.0);
int dig[20], ha[2550];
ll dp[20][50][2550];
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
{
return gcd(y, x%y);
}
}
void init()
{
int i, j, k, cnt;
memset(dp, -1, sizeof(dp));
cnt = 0;
for (i = 1; i <= 2520; i++)
{
if (mod%i == 0)
{
cnt++;
ha[i] = cnt;
}
}
}
ll dfs(ll n, ll top, ll lcm, ll mo)
{
if (n <= 0)
return mo%lcm == 0;
if (!top&&dp[n][ha[lcm]][mo] != -1)
return dp[n][ha[lcm]][mo];
int end = (top == 1) ? dig[n] : 9;
int i, j, k;
ll ans = 0;
for (i = 0; i <= end; i++)
{
int m = (mo * 10 + i) % mod;
int lcm_tmp;
if (i != 0)
lcm_tmp = lcm / gcd(lcm, i)*i;
else
lcm_tmp = lcm;
ans += dfs(n - 1, top&(i == end), lcm_tmp, m);
}
if(!top)
dp[n][ha[lcm]][mo] = ans;
return ans;
}
ll solve(ll x)
{
int i, j, k, cnt = 0;
memset(dig, 0, sizeof(dig));
while (x)
{
cnt++;
dig[cnt] = x % 10;
x /= 10;
}
ll r = dfs(cnt, 1, 1, 0);
return r;
}
int main()
{
init();
int t;
sa(t);
while (t--)
{
ll x, y;
scanf("%lld%lld", &x, &y);
printf("%lld\n", solve(y) - solve(x - 1));
}
return 0;
}