CODEFORCES 55D
问区间内有多少数能被这个数的每一位整除
#include <iostream>
#include <functional>
#include <algorithm>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <utility>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <limits>
#include <memory>
#include <string>
#include <vector>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
using namespace std;
const int MAXN=25;
const int MOD=2520;//1~9的lcm为2520
long long dp[MAXN][MOD][48];
int index[MOD+10];//记录1~9的最小公倍数
int bit[MAXN];
int gcd(int a,int b)
{
if(b==0)return a;
else return gcd(b,a%b);
}
int lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
void init()
{
int num=0;
for(int i=1;i<=MOD;i++)
if(MOD%i==0)
index[i]=num++;
}
long long dfs(int pos,int preSum,int preLcm,bool flag)//到这一位,到当前和,公倍数,有无到头
{
if(pos==-1)//如果到头了
return preSum%preLcm==0;//并且能取模,就加一
if(!flag && dp[pos][preSum][index[preLcm]]!=-1)//没到头并且记录过,记录的都是满的
return dp[pos][preSum][index[preLcm]];//返回记录值
long long ans=0;//记录答案
int endn=flag?bit[pos]:9;//如果之前的没满,上界是9,否则上界就是当前位
for(int i=0;i<=endn;i++)//对当前这位从0开始
{
int nowSum=(preSum*10+i)%MOD;//计算合
int nowLcm=preLcm;//继承公倍数
if(i)nowLcm=lcm(nowLcm,i);//计算公倍数
ans+=dfs(pos-1,nowSum,nowLcm,flag && i==endn);//向下递归
}
if(!flag)dp[pos][preSum][index[preLcm]]=ans;//如果没到头,记录的都是满的
return ans;//返回答案
}
long long calc(long long x)
{
int pos=0;
while(x)
{
bit[pos++]=x%10;
x/=10;
}
return dfs(pos-1,0,1,1);
}
int main()
{
int T;
long long l,r;
init();
memset(dp,-1,sizeof(dp));
scanf("%d",&T);
while(T--)
{
scanf("%I64d%I64d",&l,&r);
printf("%I64d\n",calc(r)-calc(l-1));
}
return 0;
}