浅谈Lucas定理(卢卡斯定理)

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_n^m=C_{a imes p+q}^{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的博客

原文地址:https://www.cnblogs.com/loceaner/p/12746161.html