#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long dp[30][30][3000];
int num[30];
long long dfs(int pos,int center,int sum,bool flag) {
//如果遍历到最后以为了
if(pos==0)
//判断和是否位0
return sum==0;
if(sum<0)
return 0;
//如果最大值没有被使用
//且之前遍历过,那么就直接拿来调用
if(!flag&&dp[pos][center][sum]!=-1)
return dp[pos][center][sum];
long long ans=0;
//判断是否为最大值
//类似于限制
//上一位是否位最大值,如果是的话,那么当前位只能取到num[pos],如果不是,那么0到9都能
//
int maxn=flag?num[pos]:9;
for(int i=0; i<=maxn; i++) {
// 位数减1
// 中心不变
// 当前位置的贡献值,如果在中心右边,就是正数,在左边,就是负数,最终答案如果是0,就是合理情况
// 最大值限制
ans+=dfs(pos-1,center,sum+i*(pos-center),i==maxn&&flag);
}//pos-center
//如果当前没限制
if(!flag)
//记录方案
dp[pos][center][sum]=ans;
return ans;
}
long long cal(long long x) {
long long ans=0;
int pos=0;
//把每一位拿出来
while(x) {
num[++pos]=x%10;
x/=10;
}
//枚举中心的位置
for(int i=1; i<=pos; i++)
//当前枚举的到的长度,
// 轴的位置
// 力矩和
// 最大位是否使用
ans+=dfs(pos,i,0,1);
//答案要去掉重复的0!!!(因为支点在每一位都有0满足情况)
return ans-pos+1;
}
int main() {
int t;
long long n,m;
memset(dp,-1,sizeof(dp));
scanf("%d",&t);
while(t--) {
scanf("%I64d%I64d",&n,&m);
printf("%I64d
",cal(m)-cal(n-1));
}
return 0;
}