卢卡斯定理(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;
}
posted @ 2020-05-15 17:29  Mcggvc  阅读(229)  评论(0编辑  收藏  举报