「笔记」浅谈Lucas定理(卢卡斯定理)
Lucas定理(卢卡斯定理)
\(\text{Lucas}\)定理是用于求 \(C^m_n\% p\) 的一种算法。
定理
当\(p\)为素数时,有\(C_{n}^{m} \equiv C_{n\%p}^{m\%p}\times C_{n/p}^{m/p}(\text{mod}\ p)\)
证明
设\(n = s\times p + q,m = t \times p + r\),有
现在我们就要证明\(C_{s\times p+q}^{t\times p+r}\equiv C_s^t\times C_q^r(\text{mod}\ p)\)
要证明这个定理,首先我们要知道费马小定理:当\(p\)为素数时,\(x^p\equiv x (\text{mod}\ p)\)。
由此我们可以知道\((1+x)^p\equiv 1 + x(\text{mod}\ p)\),并且\(x^p+1\equiv x+1(\text{mod}\ p)\),所以\((x+1)^p\equiv x^p+1\)
由上面这个性质,得\((x+1)^n\equiv(x+1)^{s\times p+q}\equiv((x+1)^p)^s\times (x+1)^q\equiv (x^p+1)^s\times (x+1)^q\)
用二项式定理展开\(\equiv \sum\limits_{i=0}^sC_s^i x ^{i\times p}\times\sum\limits_{j=0}^qC_q^jx^j\)
由上面这些可得\((x+1)^p\equiv\sum\limits_{i=0}^sC_s^i x ^{i\times p}\times\sum\limits_{j=0}^qC_q^jx^j\)
考虑把两边的多项式展开一下,那么两边肯定都有\(x^m\)即\(x^{t\times 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^m\equiv C^{m/p}_{n/p}\times C^{m\%p}_{n\%p}(\text{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 << '\n';
}
return 0;
}
证明参考自bztMinamoto的博客