当 p 为质数,1≤m≤n1≤m≤n
时,求组合数CmnmodpCnmmodp
。Lucas定理对于质数 p, 有:Cmn≡Cm/pn/p⋅Cmmodpnmodp(modp)Cnm≡Cn/pm/p⋅Cnmodpmmodp(modp)
其中n/pn/p
和 m/pm/p
为整除。证明:引理1:Cip≡pi⋅Ci−1p−1≡0(modp)Cpi≡pi⋅Cp−1i−1≡0(modp)
引理1证明:Cip=p!i!⋅(p−i)!=pi⋅(p−1)(i−1)!⋅(p−i)!Cpi=p!i!⋅(p−i)!=pi⋅(p−1)(i−1)!⋅(p−i)!
得证。
引理2:(1+x)p≡1+xp(modp)(1+x)p≡1+xp(modp)
引理2证明:(二项式定理)(1+x)p=C0p+C1p⋅x+…+Cpp⋅xp(1+x)p=Cp0+Cp1⋅x+…+Cpp⋅xp
从第二项到倒数第二项都可以在模 p 意义下消掉,只剩下第一项和最后一项,得证。Lucas定理:
令 n=s⋅p+q,m=t⋅p+rn=s⋅p+q,m=t⋅p+r
, 则s=⌊mp⌋,t=⌊mp⌋s=⌊mp⌋,t=⌊mp⌋
。(1+x)n=[(1+x)p]s⋅(1+x)q≡(1+xp)s⋅(1+x)q≡∑i=0s(Cis⋅xip)⋅∑j=0q(Cjq⋅xj)(modp)(1)(1+x)n=[(1+x)p]s⋅(1+x)q≡(1+xp)s⋅(1+x)q≡∑i=0s(Csi⋅xip)⋅∑j=0q(Cqj⋅xj)(modp)(1)
又因为:(1+x)n=(1+x)sp+q=∑k=0sp+qCksp+q⋅xk(2)(1+x)n=(1+x)sp+q=∑k=0sp+qCsp+qk⋅xk(2)
因为 (1)≡(2)(modp)(1)≡(2)(modp)
, 对比其中的 xtp+rxtp+r
项:Ctp+rsp+1⋅xtp+r≡Cts⋅xtp⋅Crq⋅xr(modp)Csp+1tp+r⋅xtp+r≡Cst⋅xtp⋅Cqr⋅xr(modp)
Ctp+rsp+1≡Cts⋅Crq(modp)Csp+1tp+r≡Cst⋅Cqr(modp)
Cmn≡Cm/pn/p⋅Cmmodpnmodp(modp)Cnm≡Cn/pm/p⋅Cnmodpmmodp(modp)
得证。于是可以递归求解。cpp:lld powe(lld a, lld b, lld p) {
lld base = 1;
while(b) {
if(b & 1) base = (base * a) % p;
a = (a * a) % p; b >>= 1;
}
return base;
}
lld comb(lld n, lld m, lld p) {
if(n < m) return 0;
if(n == m) return 1;
if(m > n - n) m = n - m;
lld cn = 1, cm = 1;
for(lld i = 0; i < m; i++) {
cn = (cn * (n - i)) % p;
cm = (cm * (i + 1)) % p;
}
return (cn * powe(cm, p - 2, p)) % p;
}
lld lucas(lld n, lld m, lld p) {
lld ans = 1;
while(n && m && ans) {
ans = (ans * comb(n % p, m % p, p)) % p;
n /= p;
m /= p;
}
return ans % p;
}
int main() {
int T; scanf("%d", &T);
while(T–) {
lld n, m, p;
scanf("%lld%lld%lld", &n, &m, &p);
printf("%lld\n", lucas(n, m, p));
}
return 0;
}