Lucas定理(卢卡斯定理)
( ext{Lucas})定理是用于求 (C^m_n\% p) 的一种算法。
定理
当(p)为素数时,有(C_{n}^{m} equiv C_{n\%p}^{m\%p} imes C_{n/p}^{m/p}( ext{mod} p))
证明
设(n = s imes p + q,m = t imes p + r),有
现在我们就要证明(C_{s imes p+q}^{t imes p+r}equiv C_s^t imes C_q^r( ext{mod} p))
要证明这个定理,首先我们要知道费马小定理:当(p)为素数时,(x^pequiv x ( ext{mod} p))。
由此我们可以知道((1+x)^pequiv 1 + x( ext{mod} p)),并且(x^p+1equiv x+1( ext{mod} p)),所以((x+1)^pequiv x^p+1)
由上面这个性质,得((x+1)^nequiv(x+1)^{s imes p+q}equiv((x+1)^p)^s imes (x+1)^qequiv (x^p+1)^s imes (x+1)^q)
用二项式定理展开(equiv sumlimits_{i=0}^sC_s^i x ^{i imes p} imessumlimits_{j=0}^qC_q^jx^j)
由上面这些可得((x+1)^pequivsumlimits_{i=0}^sC_s^i x ^{i imes p} imessumlimits_{j=0}^qC_q^jx^j)
考虑把两边的多项式展开一下,那么两边肯定都有(x^m)即(x^{t imes p+r})这一项(这是最上面的假设)
左边的(x^m)的系数,根据上面的性质推出来,应该是(C^m_n)
然后右边当(i=t,j=r)的时候才会有这一项,所以这一项的系数就是(C^t_s∗C^r_q)
然后又因为(s=n/p,t=n\%p,q=m/p,r=m\%p)
所以(C_n^mequiv C^{m/p}_{n/p} imes C^{m\%p}_{n\%p}( ext{mod} p))
代码
inline LL lucas(LL n, LL m, LL p) {
if(!m) return 1;
return C(n % p, m % p, p) * lucas(n / p, m / p, p) % p;
}
例题
此代码为洛谷P3807的代码,题目条件稍有不同,请注意
/*
Author:loceaner
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int A = 2e5 + 11;
const int B = 1e6 + 11;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int T, n, m, p, fac[A];
inline int power(int a, int b) {
int res = 1;
while (b) {
if (b & 1) res = res * a % p;
a = a * a % p, b >>= 1;
}
return res;
}
inline int C(int n, int m) {
if (m > n) return 0;
return fac[n] * power(fac[m], p - 2) % p * power(fac[n - m], p - 2) % p;
}
inline int Lucas(int n, int m) {
if (!m) return 1;
return C(n % p, m % p) * Lucas(n / p, m / p) % p;
}
inline void init() {
int maxn = p;
fac[0] = 1;
for (int i = 1; i <= maxn; i++) fac[i] = fac[i - 1] * i % p;
}
signed main() {
T = read();
while (T--) {
n = read(), m = read(), p = read();
n += m;
init();
cout << (Lucas(n, m) + p) % p << '
';
}
return 0;
}
证明参考自bztMinamoto的博客