Lucas定理:
C n m = C ⌊ n % p ⌋ ⌊ m % p ⌋ ∗ C n / p m / p C_{n}^{m} = C_{\lfloor n\%p \rfloor}^{\lfloor m\%p \rfloor} *C_{n/p}^{m/p} Cnm=C⌊n%p⌋⌊m%p⌋∗Cn/pm/p
具体计算组合数时,由于涉及到除法取模,所以可以用费马小定理求逆元。
由于
g
c
d
(
a
,
p
)
=
1
gcd(a, p) = 1
gcd(a,p)=1时,
a
p
−
1
≡
1
(
m
o
d
 
p
)
a^{p - 1} \equiv 1(mod \,p)
ap−1≡1(modp), 所以
(
n
−
m
)
!
∗
m
!
(n - m) ! * m!
(n−m)!∗m!的逆元就是
(
(
n
−
m
)
!
∗
m
!
)
p
−
2
((n - m) ! * m!)^{p - 2}
((n−m)!∗m!)p−2。
#include<cstdio>
typedef long long LL;
LL fac[100005];
LL Pow(LL a, int b, int p){
LL ans = 1; a %= p;
for(; b; b >>= 1, a = a * a % p) if(b & 1) ans = ans * a % p;
return ans;
}
LL C(LL n, LL m, int p){
if(n < m) return 0;
if(m > n - m) m = n - m;
return ((fac[n] * Pow(fac[m], p - 2, p)) % p * Pow(fac[n - m], p - 2, p)%p);
}
LL Lucas(LL n, LL m, int p){
if(!m) return 1;
return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
}
int main(){
freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while(T--){
int n, m, p;
scanf("%d%d%d", &n, &m, &p);
fac[0] = 1; for(int i = 1; i < p; i++) fac[i] = fac[i - 1] * i % p;
printf("%d\n", Lucas(n + m, m, p));
}
return 0;
}