卢卡斯定理(Lucas)
当 p 为质数,\(1 \le m \le n\) 时,求组合数\(C_{n}^{m} \bmod{p}\)。
Lucas定理
对于质数 p, 有:
\[\begin{aligned}
C_{n}^{m} \equiv C_{n / p}^{m / p} \cdot C_{n \bmod{p}}^{m \bmod {p}} \pmod{p}
\end{aligned}
\]
其中\(n / p\) 和 \(m / p\) 为整除。
证明:
引理1:
\[\begin{aligned}
C_{p}^{i} \equiv \frac{p}{i} \cdot C_{p - 1}^{i - 1} \equiv 0 \pmod{p}
\end{aligned}
\]
引理1证明:
\[\begin{aligned}
C_{p}^{i} = \frac{p!}{i! \cdot (p - i)!} = \frac{p}{i} \cdot \frac{(p - 1)}{(i - 1)! \cdot (p - i)!}
\end{aligned}
\]
得证。
引理2:
\[\begin{aligned}
(1 + x)^p \equiv 1 + x^p \pmod{p}
\end{aligned}
\]
引理2证明:(二项式定理)
\[\begin{aligned}
(1 + x)^p = C_p^0 + C_p^1 \cdot x + ... + C_p^p \cdot x^p
\end{aligned}
\]
从第二项到倒数第二项都可以在模 p 意义下消掉,只剩下第一项和最后一项,得证。
Lucas定理:
令 \(n = s \cdot p + q, m = t \cdot p + r\), 则\(s = \left \lfloor \frac{m}{p} \right \rfloor, t = \left \lfloor \frac{m}{p} \right \rfloor\)。
\[\begin{aligned}
(1 + x)^n = [(1 + x)^p]^s \cdot (1 + x)^q \equiv (1 + x^p) ^ s \cdot (1 + x) ^ q \equiv \sum_{i = 0}^{s} (C_s^i \cdot x^{ip}) \cdot \sum_{j = 0} ^ q (C_{q}^{j} \cdot x^j) \pmod{p} \qquad (1)
\end{aligned}
\]
又因为:
\[\begin{aligned}
(1 + x) ^ n = (1 + x)^{sp + q} = \sum_{k = 0} ^ {sp + q} C_{sp + q} ^ {k} \cdot x^k \qquad (2)
\end{aligned}
\]
因为 \((1) \equiv (2) \pmod{p}\) , 对比其中的 \(x^{tp + r}\)项:
\[\begin{aligned}
C_{sp + 1} ^ {tp + r} \cdot x ^ {tp + r} \equiv C_s^t \cdot x^{tp} \cdot C_q^ r \cdot x^r \pmod{p}
\end{aligned}
\]
\[\begin{aligned}
C_{sp + 1} ^ {tp + r} \equiv C_s^t \cdot C_q^ r \pmod{p}
\end{aligned}
\]
\[\begin{aligned}
C_{n}^{m} \equiv C_{n / p}^{m / p} \cdot C_{n \bmod{p}}^{m \bmod {p}} \pmod{p}
\end{aligned}
\]
得证。
于是可以递归求解。
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 - m) 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;
}