传送门:HDU-6093
题意:如果一个数在某一进制d下所有位是0~d-1的排列,则称这个数为“好数”,问[L,R]之间有多少个“好数”
题解:计数/数位dp
由于L和R很大(L,R<=10^5000)因此需要用大数模拟,用[1,R]内的数量减去[1,L]内的数量即可。
首先可以猜一个结论:每一个数之多只在一个d进制下能形成0~d-1的全排列。其证明也很简单:如果一个数在d进制下是“好数”,那么这个数一定在(d^(d-1),d^d]之间,因此d进制和d-1进制的区间是不想交的,猜想得证。
然后可以打表得出每一进制下数字的长度,如果d进制数字长度小于n的数字长度则区间[1,n]一定可以包含所有d进制的“好数”(注意:当d=3或d=4时要特判一下,因为d=3时区间为[11,27],d=4时区间为[75,256]都包含了长度为2的数字)
易知d进制的所有“好数”有d!-(d-1)!,因此只要特殊处理临界状态的计数即可。这个计数和数位dp差不多,具体看代码。要注意的是当枚举到最低位时需要特殊处理
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MX = 7e3 + 5;
const LL mod = 998244353;
const int MAXN = 9999;
const int DLEN = 4;
class Big {
public:
int a[MX], len;
Big(const int b = 0) {
int c, d = b;
len = 0;
memset(a, 0, sizeof(a));
while (d > MAXN) {
c = d - (d / (MAXN + 1)) * (MAXN + 1);
d = d / (MAXN + 1);
a[len++] = c;
}
a[len++] = d;
}
Big(const char *s) {
int t, k, index, L, i;
memset(a, 0, sizeof(a));
L = strlen(s);
len = L / DLEN;
if (L % DLEN) len++;
index = 0;
for (i = L - 1; i >= 0; i -= DLEN) {
t = 0;
k = i - DLEN + 1;
if (k < 0) k = 0;
for (int j = k; j <= i; j++) t = t * 10 + s[j] - '0';
a[index++] = t;
}
}
bool operator>(const Big &T)const {
int ln;
if (len > T.len) return true;
else if (len == T.len) {
ln = len - 1;
while (a[ln] == T.a[ln] && ln >= 0) ln--;
if (ln >= 0 && a[ln] > T.a[ln]) return true;
else return false;
} else return false;
}
bool operator==(const Big &T)const {
int ln;
if (len == T.len) {
ln = len - 1;
while (a[ln] == T.a[ln] && ln >= 0) ln--;
return ln < 0;
} else return false;
}
Big operator-(const Big &T)const {
int i, j, big;
bool flag;
Big t1, t2;
if (*this > T) {
t1 = *this;
t2 = T;
flag = 0;
} else {
t1 = T; t2 = *this; flag = 1;
}
big = t1.len;
for (i = 0; i < big; i++) {
if (t1.a[i] < t2.a[i]) {
j = i + 1;
while (t1.a[j] == 0) j++;
t1.a[j--]--;
while (j > i) t1.a[j--] += MAXN;
t1.a[i] += MAXN + 1 - t2.a[i];
} else t1.a[i] -= t2.a[i];
}
t1.len = big;
while (t1.a[t1.len - 1] == 0 && t1.len > 1) {
t1.len--;
big--;
}
if (flag) t1.a[big - 1] = 0 - t1.a[big - 1];
return t1;
}
int operator%(const int &b)const {
int i, d = 0;
for (int i = len - 1; i >= 0; i--) d = ((d * (MAXN + 1)) % b + a[i]) % b;
return d;
}
Big operator/(const int &b)const {
Big ret;
int i, down = 0;
for (int i = len - 1; i >= 0; i--) {
ret.a[i] = (a[i] + down * (MAXN + 1)) / b;
down = a[i] + down * (MAXN + 1) - ret.a[i] * b;
}
ret.len = len;
while (ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--;
return ret;
}
void print() {
printf("%d", a[len - 1]);
for (int i = len - 2; i >= 0; i--) printf("%04d", a[i]);
}
};
LL f[MX];
char L[MX], R[MX];
int n, d, a[MX], c[MX], e[MX], vis[MX], t[MX];
bool cmp(int a[], int b[]) {
for (int i = d; i >= 1; i--) if (a[i] != b[i]) return a[i] > b[i];
return 1;
}
void get_len(Big b) {
n = (b.len - 1) * 4;
if (b.a[b.len - 1] >= 1000) n += 4;
else if (b.a[b.len - 1] >= 100) n += 3;
else if (b.a[b.len - 1] >= 10) n += 2;
else n++;
}
LL cal(Big b, int d) {
int len = 0;
LL ans = 0;
while (b > 0) a[++len] = b % d, b = b / d;
for (int i = d; i >= 1; i--) c[i] = i - 1, e[i] = d - i;
swap(e[d], e[d - 1]);
if (len > d || cmp(a, c)) ans = (ans + f[d] - f[d - 1]) % mod;
else if (len == d && cmp(a, e)) {
LL cnt;
memset(vis, 0, sizeof(vis));
for (int i = len; i >= 1; i--) {
if (i == len) cnt = a[i] - 1;
else {
cnt = 0;
for (int j = 0; j < a[i]; j++) if (!vis[j]) cnt++;
if (i == 1) for (int j = 0; j <= a[i]; j++) if (!vis[j]) cnt = 1;
}
ans = (ans + cnt * f[i - 1]) % mod;
if (vis[a[i]]) break;
vis[a[i]] = 1;
}
}
return ans;
}
LL solve(Big b) {
if (b == 0 || b == 1) return 0;
get_len(b);
LL ans = 0;
if (n == 2) {
if (b > 10) d = 3;
if (b > 74) d = 4;
} else
for (d = 2; d < MX && t[d] < n; d++);
for (int i = 2; i < d - 1; i++) ans = (ans + f[i] - f[i - 1] + mod) % mod;
if (d > 2) ans = (ans + cal(b, d - 1)) % mod;
ans = (ans + cal(b, d)) % mod;
return ans;
}
void init() {
f[0] = 1;
for (int i = 1; i < MX; i++) f[i] = f[i - 1] * i % mod;
for (int i = 2; i < MX; i++) t[i] = i * log10(1.0 * i);
}
int main() {
int T;
//freopen("in.txt", "r", stdin);
init();
cin >> T;
while (T--) {
scanf("%s%s", L, R);
Big l = L, r = R;
printf("%lld\n", (solve(r) - solve(l - 1) + mod) % mod);
}
return 0;
}