浅谈我对(扩展)Lucas定理的理解

本文深入探讨了Lucas定理在组合数取模运算中的应用,通过分解模数并利用中国剩余定理,提出了一种求解Cnm(mod p)的有效算法,适用于质数p较小的情况。

可能是太太太久没有用这个定理了,考场上都不记得有这个东西,然后自己推了个组合数取模(模数是一个质数p,且p比较小),考后发现就是Lucas定理,可以说是顺推出了Lucas定理,而不是有了结论再去证明。


目标:
C n m ( m o d   p ) C_{n}^m(mod~p) Cnm(mod p),p是质数,且比较小。

step1:

考虑如何求 n ! ( m o d   p ) n!(mod~p) n!(mod p)

当然是把p的倍数先提出来,然后剩下的数 m o d   p mod~p mod p之后就是 1 , 2 , … , p − 1 1,2,…,p-1 1,2,,p1的周期。

n ! ( m o d   p ) n!(mod~p) n!(mod p)
= ( p − 1 ) ! n / p ∗ ( n   m o d   p ) ! ∗ p n / p ∗ ( n / p ) ! =(p-1)!^{n/p}*(n~mod~p)!*p^{n/p}*(n/p)! =(p1)!n/p(n mod p)!pn/p(n/p)!

step2:

C n m ( m o d   p ) C_{n}^m(mod~p) Cnm(mod p)
n ! m ! ∗ ( n − m ) ! {n!\over m!*(n-m)!} m!(nm)!n!

先考虑它含 p p p的幂次为0的条件是什么?
就是 ( n / p − m / p − ( n − m ) / p ) = 0 (n/p-m/p-(n-m)/p)=0 (n/pm/p(nm)/p)=0
那么其实就是 n   m o d   p > = m   m o d   p n~mod~p>=m~mod~p n mod p>=m mod p

因为 n / p = m / p + ( n − m ) / p n/p=m/p+(n-m)/p n/p=m/p+(nm)/p,所以刚才 n ! n! n!中的 ( p − 1 ) ! n / p (p-1)!^{n/p} (p1)!n/p这一项就被消掉了。

再代入得:
= [ n   m o d   p > = m   m o d   p ] ∗ ( n   m o d   p ) ! ( m   m o d   p ) ! ∗ ( ( n − m )   m o d   p ) ! ∗ ( n / p ) ! ( m / p ) ! ∗ ( ( n − m ) / p ) ! = [n~mod~p>=m~mod~p]* {(n~mod~p)!\over(m~mod~p)!*((n-m)~mod~p)!} *{(n/p)!\over(m/p)!*((n-m)/p)!} =[n mod p>=m mod p](m mod p)!((nm) mod p)!(n mod p)!(m/p)!((nm)/p)!(n/p)!

[ n   m o d   p > = m   m o d   p ] ∗ ( n   m o d   p ) ! ( m   m o d   p ) ! ∗ ( ( n − m )   m o d   p ) ! [n~mod~p>=m~mod~p]* {(n~mod~p)!\over(m~mod~p)!*((n-m)~mod~p)!} [n mod p>=m mod p](m mod p)!((nm) mod p)!(n mod p)! C n   m o d   p m   m o d   p C_{n~mod~p}^{m~mod~p} Cn mod pm mod p

[ n   m o d   p > = m   m o d   p ] ∗ ( n / p ) ! ( m / p ) ! ∗ ( ( n − m ) / p ) ! ⇔ C n / p m / p [n~mod~p>=m~mod~p]*{(n/p)!\over(m/p)!*((n-m)/p)!}⇔C_{n/p}^{m/p} [n mod p>=m mod p](m/p)!((nm)/p)!(n/p)!Cn/pm/p
整理得:
C n m = C n   m o d   p m   m o d   p ∗ C n / p m / p C_{n}^{m}=C_{n~mod~p}^{m~mod~p}*C_{n/p}^{m/p} Cnm=Cn mod pm mod pCn/pm/p


有了上面的思路扩展Lucas定理就是手到擒来的。

我想扩展Lucas并不用给出Lucas定理那样优美的式子,只要能看就行了。

首先对模数分解质因数,之后(ex)中国剩余定理合并回去就行了。

现在问题在于求 C n m   m o d   p k C_{n}^{m}~mod~p^k Cnm mod pk, p p p是一个质数。

n !   m o d   p k n!~mod~p^k n! mod pk
= ( ∏ i = 1 且 i   m o d   p > 0 p k ∗ i ) n / p k ∗ ( ∏ i = 1 且 i   m o d   p > 0 n   m o d   p k ∗ i ) ∗ ( n / p ) ! ∗ p n / p =(\prod_{i=1且i~mod~p>0}^{p^k}*i)^{n/{p^k}}*(\prod_{i=1且i~mod~p>0}^{n~mod~p^k}*i)*(n/p)!*p^{n/p} =(i=1i mod p>0pki)n/pk(i=1i mod p>0n mod pki)(n/p)!pn/p

( n / p ) ! (n/p)! (n/p)!可能产生新的 p p p的倍数,这个可以递归解决。

我们可以求出这样一个形式,即 n ! = p x ∗ y ( y ≠ 0 ) n!=p^{x}*y(y≠0) n!=pxy(y̸=0),然后:
C n m = n ! m ! ∗ ( n − m ) ! C_{n}^m={n! \over m!*(n-m)!} Cnm=m!(nm)!n!

这样 p p p的幂次用上面-下面算,然后y有逆元的,逆元的话可以用欧拉定理,如果写的是excrt,也可以直接用,这样就做完了。

洛谷模板题:
https://www.luogu.org/problemnew/show/P4720

Code:

#include<cstdio>
#define pp printf
#define ll long long
#define fo(i, x, y) for(ll i = x, B = y; i <= B; i ++)
using namespace std;

ll n, m, p;
ll mo;

ll gcd(ll x, ll y) {
	return !y ? x : gcd(y, x % y);
}
void eg(ll a, ll b, ll &x, ll &y) {
	if(!b) {x = a; y = 0; return;}
	eg(b, a % b, y, x); y -= a / b * x;
}
ll inv(ll u, ll v) {
	ll x, y; eg(u, -v, x, y);
	return (x % v + v) % v;;
}
ll ksm(ll x, ll y) {
	ll s = 1;
	for(; y; y /= 2, x = x * x % mo)
		if(y & 1) s = s * x % mo;
	return s;
}

struct crt {
	ll c, m;
	crt(ll _c = 0, ll _m = 0) {m = _m, c = _c;}
};

crt excrt(crt a, crt b) {
	ll t = gcd(a.m, b.m);
	ll m3 = b.m / t, M = m3 * a.m;
	crt c;
	c.c = ((ll) inv(a.m / t, m3) * ((b.c - a.c) / t) % m3 * a.m + a.c) % M;
	c.c < 0 ? c.c += M : 0;
	c.m = M; return c;
}

ll fc1(ll n, ll p) {
	return !n ? 0 : n / p + fc1(n / p, p);
}
ll fc2(ll n, ll p) {
	if(!n) return 1;
	ll s = 1;
	fo(i, 1, mo) if(i % p) s = s * i % mo;
	s = ksm(s, n / mo);
	fo(i, 1, n % mo) if(i % p) s = s * i % mo;
	return s * fc2(n / p, p) % mo;
}
ll C(ll n, ll m, ll p, ll k) {
	mo = 1; fo(i, 1, k) mo = mo * p;
	ll x = fc1(n, p) - fc1(m, p) - fc1(n - m, p);
	if(x >= k) return 0;
	ll y = fc2(n, p) * inv(fc2(m, p) * fc2(n - m, p) % mo, mo) % mo;
	return ksm(p, x) * y % mo;
}

crt a, b;

int main() {
	scanf("%lld %lld %lld", &n, &m, &p);
	a = crt(0, 1);
	fo(i, 2, p) if(p % i == 0) {
		ll u = i, v = 0, g = 1;
		while(p % i == 0) v ++, p /= i, g *= i;
		b = crt(C(n, m, u, v), g);
		a = excrt(a, b);
	}
	pp("%lld\n", a.c);
}
<think>嗯,用户想了解Lucas定理,涉及数学、计算机科学、组合数和取模运算。我需要先回忆一下Lucas定理的基本内容和应用场景。首先,Lucas定理是用来计算组合数取模的一个方法,特别是当模数是质数的时候。这个定理在组合数学和算法竞赛中应该比较常见,因为处理大数组合数取模的问题时,直接计算可能会非常耗时或者溢出,所以需要高效的算法。 根据用户提供的引用,特别是引用[3]提到数论是算法竞赛的重要部分,Lucas定理作为数论中的一个定理,可能在竞赛中用于解决组合数取模的问题。用户的问题涉及组合数和取模运算,所以需要详细说明定理的表述、证明思路以及实际应用方法。 首先,Lucas定理的具体内容是什么?我记得定理指出,对于质数p,将两个非负整数m和n表示为p进制展开,即m = m_k p^k + ... + m_0,n = n_k p^k + ... + n_0,那么组合数C(m, n) mod p等于各个对应位组合数C(m_i, n_i)的乘积再mod p。如果某一位的n_i > m_i,则整个组合数mod p为0。 接下来需要解释定理的数学表达式,用LaTeX写成独立公式。比如: $$ \binom{m}{n} \equiv \prod_{i=0}^k \binom{m_i}{n_i} \pmod{p} $$ 其中,m_i和n_i是m和n在p进制下的各位数字。这个表达式需要正确使用$$...$$格式,并且单独成段。 然后,定理的证明思路是怎样的?通常,证明会用到生成函数或者多项式展开,利用二项式定理在模p下的性质。例如,考虑多项式(1 + x)^m在模p下的展开,并分解为各个p进制位的乘积。这部分可能需要引用二项式定理Lucas的原始论文,但用户提供的引用中没有直接相关的,所以可能需要简要说明证明的大致步骤,而不过多深入细节。 应用场景方面,用户可能关心的是在算法竞赛中如何用Lucas定理快速计算组合数模质数的情况。例如,当需要计算C(n, k) mod p,其中p是质数,且n和k很大(比如1e18),这时候直接计算不可行,使用Lucas定理可以将问题分解为多个小规模的组合数计算,这些小组合数可以通过预计算阶乘和逆元来处理。 在步骤解释时,需要分步说明如何应用Lucas定理。例如: 1. 将n和k转换为p进制数。 2. 对每一位计算组合数C(n_i, k_i) mod p。 3. 将所有结果相乘再mod p得到最终结果。 可能还需要提到如何处理n_i < k_i的情况,这时候组合数为0,整个乘积也为0,因此直接返回0。 然后,给出一个具体的例子,比如计算C(12, 5) mod 3。将12和5转换为3进制,得到12=110_3,5=12_3。然后对应每一位的组合数:C(1,1)=1,C(1,2)=0(因为1<2),所以结果为1*0=0 mod 3。但这里可能需要注意位数对齐的问题,可能需要补前导零,比如5在3进制下是12,而12在3进制下是110,位数不同,所以需要将5补为012。然后每位组合数分别是C(1,0)=1,C(1,1)=1,C(0,2)=0,所以乘积是1*1*0=0。这个例子可能需要更详细地说明步骤,避免混淆。 接下来,可能需要给出代码示例,比如用递归或迭代的方式实现Lucas定理。代码部分需要用Python展示,并注意语法正确。例如,一个递归实现的Lucas函数,其中comb函数用于计算小规模的组合数mod p,可能需要预处理阶乘和逆元来提高效率。 此外,需要指出Lucas定理的限制,比如p必须是质数,如果p不是质数,则需要使用其他方法如中国剩余定理分解模数。这可能关联到引用[2]中提到的梅森素数判断中的模运算问题,但用户的问题中没有提到,所以可能不需要深入展开。 最后,生成相关问题需要考虑用户可能的后续疑问,比如Lucas定理扩展应用、与其他定理(如中国剩余定理)的结合使用、处理非质数模数的方法、算法的时间复杂度以及优化技巧等。例如: 1. Lucas定理能否处理模数为合数的情况? 2. 如何结合中国剩余定理处理大数组合数取模? 3. 有没有比Lucas定理更高效的组合数取模算法? 4. Lucas定理的递归实现和迭代实现哪种更好? 需要确保这些问题与Lucas定理相关,并且能引导用户进一步深入学习。 总结,回答的结构应该包括定理的表述、证明思路、应用方法、实例演示、代码实现、应用场景以及相关问题。需要确保所有数学公式正确使用$...$或$$...$$,引用文献适当,并且回答符合用户要求的结构清晰和真实可靠。</think>### Lucas定理详解 Lucas定理是数论中用于高效计算组合数取模的重要工具,尤其适用于模数$p$为质数的情况。其核心思想是将大数分解为$p$进制各位的组合数乘积,从而降低计算复杂度[^3]。 #### 定理表述 设$p$为质数,$m,n$为非负整数,将其表示为$p$进制展开: $$ m = m_kp^k + m_{k-1}p^{k-1} + \dots + m_0 \\ n = n_kp^k + n_{k-1}p^{k-1} + \dots + n_0 $$ 则组合数满足: $$ \binom{m}{n} \equiv \prod_{i=0}^k \binom{m_i}{n_i} \pmod{p} $$ 若存在某位$n_i > m_i$,则$\binom{m}{n} \equiv 0 \pmod{p}$[^1]。 #### 证明思路 1. **多项式展开**:利用二项式定理展开$(1+x)^m$,在模$p$环境下分析系数 2. **生成函数分解**:将$(1+x)^m$分解为$p$进制各位的乘积形式 3. **系数对应**:通过比较系数得到组合数的分解关系 #### 应用步骤 以计算$\binom{12}{5} \mod 3$为例: 1. **转换进制**:$12=1\cdot3^2 + 1\cdot3^1 + 0\cdot3^0$,$5=0\cdot3^2 +1\cdot3^1 +2\cdot3^0$ 2. **逐位计算**: - $\binom{1}{0}=1$ - $\binom{1}{1}=1$ - $\binom{0}{2}=0$ 3. **结果相乘**:$1\times1\times0 \equiv 0 \mod 3$ #### 代码实现 ```python def comb(n, k, p): if k > n: return 0 # 预计算阶乘和逆元更高效 numerator = 1 for i in range(k): numerator = numerator * (n-i) % p denominator = 1 for i in range(1, k+1): denominator = denominator * i % p return numerator * pow(denominator, p-2, p) % p # 费马小定理求逆元 def lucas(n, k, p): if k == 0: return 1 return comb(n%p, k%p, p) * lucas(n//p, k//p, p) % p ``` #### 应用场景 - **算法竞赛**:处理$n,k$极大(如$10^{18}$)的组合数取模问题 - **密码学**:构造特定数学结构的加密算法 - **概率计算**:大样本空间下的离散概率计算
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值