卢卡斯定理
( 不是卢斯卡...
求组合数模数的方法
\[C_m^n = \dfrac {m!} {n!(m-n)!}
\]
一般情况下对一个大素数 \(p\) 取模, 可以线性处理出阶乘,阶乘的逆元, \(O(1)\) 计算就可以。
const int N = 1e6 + 10;
int fac[N],invfac[N],inv[N];
const int mod = 998244353;
void init(){
fac[0] = invfac[0] = 1;
fac[1] = invfac[1] = 1;
inv[1] = 1;
for(int i = 2;i < N;i++){
fac[i] = fac[i-1] * i % mod;
inv[i] = (mod - mod / i)*inv[mod % i] % mod;
invfac[i] = invfac[i-1] * inv[i] % mod;
}
}
int C(int n,int m){
return fac[n]*invfac[n-m]*invfac[m];
}
但是, 当 \(p < m\) 的时候,就需要用 \(Lucas\) 了
\[C_m^n = C_{m\%p}^{n\%p} \cdot \ C_{m/p}^{n/p} \ \ (mod\ \ p)
\]
/*
* @Author: zhl
* @Date: 2020-11-12 10:27:57
*/
#include<bits/stdc++.h>
using ll = long long;
using namespace std;
const int N = 1e6 + 10;
ll fac[N], invfac[N], inv[N];
void init(int n, int mod) {
fac[0] = invfac[0] = 1;
fac[1] = invfac[1] = 1;
inv[1] = 1;
for (int i = 2; i < n; i++) {
fac[i] = fac[i - 1] * i % mod;
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
invfac[i] = invfac[i - 1] * inv[i] % mod;
}
}
// 需要先预处理出fact[],即阶乘
ll C(ll m, ll n, ll p){
return m < n ? 0 : fac[m] * invfac[n] % p * invfac[m - n] % p;
}
ll lucas(ll m, ll n, ll p){
return n == 0 ? 1 % p : lucas(m / p, n / p, p) * C(m % p, n % p, p) % p;
}
int T, n, m, k;
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d%d%d", &n, &m, &k);
init(n + m + 1, k);
printf("%lld\n", lucas(n + m, n, k));
}
}