Forever Young

「笔记」浅谈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_n^m=C_{a\times p+q}^{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的博客

posted @ 2020-04-21 17:34  Loceaner  阅读(338)  评论(2编辑  收藏  举报