题解
用lucas随便分析一波就出来了
(inom{n}{k} = inom{n % p}{k % p}inom{n / p}{k / p})
那么对于一个余数r,如果r <= k % p
那么它还要乘上
(sum_{i = 0}^{lfloor frac{k}{p}
floor} inom{lfloor frac{n}{p}
floor % p}{i})
这显然是个相同的问题,可以递归
如果r > k % p那么会比前一个问题少乘一个(inom{lfloor frac{n}{p}
floor % p}{lfloor frac{k}{p}
floor})
这样我们处理下2333以内每行组合数的前缀和,再递归处理,可以用(log^2 n)的复杂度内解决,但是别忘了底数是p,超级快的。。。
代码
#include <bits/stdc++.h>
#define enter putchar('
')
#define space putchar(' ')
#define pii pair<int,int>
#define fi first
#define se second
#define MAXN 200005
#define pb push_back
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
const int MOD = 2333;
int C[2335][2335],S[2335][2335];
int inc(int a,int b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
return a * b % MOD;
}
int Cnm(int64 n,int64 m) {
int res = 1;
while(1) {
if(n < m || !res) {return 0;}
if(n == 0) break;
res = mul(res,C[n % MOD][m % MOD]);
n /= MOD;m /= MOD;
}
return res;
}
int Calc(int64 n,int64 k) {
if(!n) return 1;
int64 t = k / MOD;int r = k % MOD;
int h2 = Cnm(n / MOD,t);
int h1 = Calc(n / MOD,t);
h2 = inc(h1,MOD - h2);
return inc(mul(S[n % MOD][r],h1),mul(inc(S[n % MOD][MOD - 1],MOD - S[n % MOD][r]),h2));
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
C[0][0] = 1;
for(int i = 1 ; i < MOD ; ++i) {
C[i][0] = 1;
for(int j = 1 ; j <= i ; ++j) {
C[i][j] = inc(C[i - 1][j - 1],C[i - 1][j]);
}
}
for(int i = 0 ; i < MOD ; ++i) {
S[i][0] = 1;
for(int j = 1 ; j < MOD ; ++j) {
S[i][j] = inc(S[i][j - 1],C[i][j]);
}
}
int T;
int64 N,K;
read(T);
while(T--) {
read(N);read(K);
out(Calc(N,K));enter;
}
return 0;
}