定义Classy Integer为不超过三个数位为非零数的数。给出q次询问,每次要求给出[l,r]区间中Classy Integer的数目。
计算[l,r]的结果,考虑以cal(r)-cal(l)的形式给出。考虑某个数字的前缀有k个非0的数位,后缀的长度为x,且前缀之后第一位为d的情况。如果d为0,这个时候显然答案为0,。否则,因为我们要计算的是[1,r]区间的答案,在小于r的情况下就可以在d这个位置填0~d-1的数。填0的时候,就在后面的x-1位中选若干位填非0数,否则也同理。
容易得出cal(n)的答案是
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 300050;
const ll INF = (1LL << 62) - 1;
const double eps = 1e-8;
int t, p9[5] = {1, 9, 81, 729};
char s[105];
ll L, R;
ll C(int a, int b)
{
if(a < b || a < 0 || b < 0) return 0;
if(b == 0 || a == b) return 1;
ll tmp = 1;
for(int i = a;i > a - b;i--) tmp *= i;
for(int i = 1;i <= b;i++) tmp /= i;
return tmp;
}
ll getnum(int n, int m)
{
ll res = 0;
for(int i = 0;i <= m;i++)
res += C(n, i)*p9[i];
return res;
}
ll cal(ll n)
{
memset(s, 0, sizeof(s));
int num = 0, cur = 3;
ll tmp = n, res = 0;
while(tmp) {s[num++] = '0' + tmp % 10; tmp /= 10;}
for(int i = num - 1;i >= 0;i--)
{
if(s[i] == '0') continue;
res += getnum(i, cur);
cur--;
if(cur < 0) break;
res += getnum(i, cur)*(s[i] - '1');
}
return res;
}
int main()
{
scanf("%d", &t);
while(t--)
{
scanf("%I64d%I64d", &L, &R);
ll ans = cal(R + 1) - cal(L);
printf("%I64d\n", ans);
}
return 0;
}