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
数位DP经典好题。 首先状态不好想。 dp[i][j][k] 表示到弟i位对2520取模后为j,各位的lcm为k的数字个数。
为什么要这样是因为同余定理(a*10 + b)%2520 = (a%2520*10 + b) % 2520 。因为1-9的最小公倍数不会超过2520,
那么就可以写出式子。 还有个优化。因为19*2520*2520太大, 会mle, 所以可以优化下第三维,因为最小公倍数都是离散的, 所以可以hash记录下。
#include <bits/stdc++.h>
using namespace std;
int num[20];
long long dp[20][2522][49];
int __lcm(int a, int b){
return a/__gcd(a, b)*b;
}
int Index[2522];
void init(){
int te = 1;
for(int i=1; i<=2520; i++)
if(2520%i == 0)
Index[i] = te++;
}
long long dfs(int i, int p, int lcm, bool e) {
if (i==-1) return p%lcm == 0;
if (!e && ~dp[i][p][Index[lcm]]) return dp[i][p][Index[lcm]];
long long res = 0;
int u = e?num[i]:9;
for (int d = 0; d <= u; ++d){
int nowlcm = lcm;
if(d) nowlcm = __lcm(nowlcm, d);
res += dfs(i-1, (p*10+d)%2520, nowlcm,e&&d==u);
}
return e?res:dp[i][p][Index[lcm]] = res;
}
long long solve(long long x){
int t = 0;
while(x){
num[t++] = x%10;
x /= 10;
}
return dfs(t-1, 0, 1, true);
}
int main(){
int T;
cin>>T;
init();
memset(dp, -1, sizeof(dp));
while(T--){
long long a,b;
cin>>a>>b;
cout<<solve(b) - solve(a-1)<<endl;
}
return 0;
}