題目鏈接: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));
}
}