我们发现暴力+裸的卢卡斯可以骗到50分
所以就应该朝卢卡斯的方向去想。
卢卡斯是把n,k拆成两个p进制数进行统计的。
注意到如果在某一位 a i > n i a_i>n_i ai>ni,a表示当前的数,n就是给定的n,那么这个数就肯定是0。
所以在p进制时n就是k的限制。
有可以发现这和数位dp很像,所以用数位dp求解就行了。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
const int N = 1e6 + 10;
const int p = 2333;
ll n, k;
int c[p][p], a[11], b[11], d[11];
void solve() {
scanf("%lld%lld", &n, &k);
for (int i = 1; i <= 6; i++) {
a[i] = int(n % (ll)p);
b[i] = int(k % (ll)p);
n /= (ll)p, k /= (ll)p;
}
d[0] = 1;
for (int i = 1; i <= 6; i++)
d[i] = d[i - 1] * c[a[i]][a[i]] % p;
int ans = 0, now = 1;
for (int i = 6; i >= 1; i--) {
if (b[i] > a[i]) {
(ans += now * d[i] % p) %= p;
cout << ans << endl;
return;
}
if (b[i] > 0) {
(ans += now * c[a[i]][b[i] - 1] % p * d[i - 1] % p) % p;
now = now * ((c[a[i]][b[i]] - c[a[i]][b[i] - 1] + p) % p) % p;
}
}
ans = (ans + now) % p;
cout << ans << endl;
}
int main() {
c[0][0] = 1;
for (int i = 1; i < p; i++) {
c[i][0] = 1;
for (int j = 1; j <= i; j++)
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % p;
}
for (int i = 1; i < p; i++)
for (int j = 1; j <= i; j++)
c[i][j] = (c[i][j] + c[i][j - 1]) % p;
int tt; cin >> tt;
while (tt--) solve();
return 0;
}