题目链接:http://codeforces.com/contest/55/problem/D
题目简述:求[a,b]区间内整数n,n能被他所有非零数位上的数整除。
看见整除,肯定想的就是%i=0,所以要记他%1~9的余数,但这明显是不科学的。。
于是乎,只需要记下1~9的LCM,LCM=2520,这样状态就小了很多了,到最后再分开模。
但是我怎么知道他有1~9中的哪些?。。可以考虑状压,其实挺好。
但还有更好的方法,就是再记录一个选中的数的LCM,刚刚%2520的数再来模这个LCM如果是0那么肯定就对了。反之亦然。
1~9选出一些数的LCM其实只有48个,这样复杂度又压了很多。
状态就是F[i][MOD][LCM]
记忆化搜索真心很无脑啊,随便搞搞,边界条件设一下就等他自己跑就行了。。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define rep(i,l,r) for (int i=l;i<=r;++i)
typedef long long LL;
const int MOD=2520;
int LCM[2521],num=0;
LL f[20][2521][49],a[20];
LL pow[20];
int Gcd(int a,int b){return !b?a:Gcd(b,a%b);}
int Lcm(int a,int b){return a*b/Gcd(a,b);}
void Prep(){
memset(f,-1,sizeof f);
pow[1]=1;
rep(i,2,20) pow[i]=pow[i-1]*10%MOD;
rep(i,1,MOD) if (MOD%i==0) LCM[i]=++num;
}
LL dfs(int pos,int mod,int lcm,bool lim){
if (pos==0) return mod%lcm==0;
if (!lim&&~f[pos][mod][LCM[lcm]]) return f[pos][mod][LCM[lcm]];
int top=lim?a[pos]:9;LL res=0;
rep(i,0,top){
if (i==0) res+=dfs(pos-1,mod,lcm,lim&&i==top);
else{
int M=(mod+pow[pos]*i)%MOD;
res+=dfs(pos-1,M,Lcm(lcm,i),lim&&i==top);
}
}
return lim?res:(f[pos][mod][LCM[lcm]]=res);
}
LL count(LL x){
int len=0;
while (x) a[++len]=x%10,x/=10;
return dfs(len,0,1,1);
}
int main(){
Prep();
int T;scanf("%d",&T);
while (T--){
LL l,r;
scanf("%I64d%I64d",&l,&r);
printf("%I64d\n",count(r)-count(l-1));
}
}