题目描述
Volodya是一个很皮的男♂孩。他认为一个能被它自己的每一位数上的数整除的数是很妙的。我们先忽略他的想法的正确性(如需证明请百度“神奇海螺”),只回答在l到r之间有多少个很妙的数字。
输入输出格式
输入:总共有t个询问:
第一行:t;
接下来t行:每行两个数l和r。
注意:请勿使用%lld读写长整型(虽然我也不知道为什么),请优先使用cin(或者是%I64d)。
输出:t行,每行为一个询问的答案。
输入输出样例
输入 #1复制
1
1 9
输出 #1复制
9
输入 #2复制
1
12 15
输出 #2复制
2
这是一道数位DP题,大体上只要把数位DP记忆化搜索的板子改一改就行了
首先我们确定DP方程,他要求被可以被每一位的最小公倍数整除,因此我们需要开十以内的最小公倍数2520的内存来存储当前数除以2520的余数,另外还要存储从头开始的pos位置。此外,我们还需要存储到目前pos位置处的最小公倍数是多少,由于这里的最小公倍数并不连续,而是离散的,因此我们需要对其使用离散化处理,记住map不能用,会超时…
然后套一个数位DP的模板即可
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 22;
const int M = 55;
int T,n,m,a[N],f[N][2522][M];
vector<int> alls;
int hsh[2522];
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int llcm(int a,int b){
return a/gcd(a,b)*b;
}
void init(){
memset(f,-1,sizeof f);
for(int i=1,j=0;i<=2520;i++)
if(2520%i==0) hsh[i]=j++;
}
int dp(int pos,int mod,int lcm,bool flag){
if(pos==0) return mod%lcm==0;
if(flag&&f[pos][mod][hsh[lcm]]!=-1) return f[pos][mod][hsh[lcm]];
int x= flag?9:a[pos];
int ans=0;
for(int i=0;i<=x;i++){
int tlcm = i?llcm(lcm,i):lcm;
int tmod = (mod*10+i)%2520;
ans+=dp(pos-1,tmod,tlcm,flag||i<x);
}
if(flag) f[pos][mod][hsh[lcm]]=ans;
return ans;
}
int calc(int x){
memset(a,0,sizeof a);
int pos=0;
while(x){
a[++pos]=x%10;
x/=10;
}
return dp(pos,0,1,0);
}
signed main(){
init();
cin >> T;
while(T--){
cin >> n >> m;
cout << calc(m)-calc(n-1) << endl;
}
return 0;
}