【数学】扩展卢卡斯定理

Description


( n m )   m o d   p \dbinom{n}{m}\bmod p (mn)modp
其中 p p p 较小且 不保证 p p p 是质数。

Method

前置芝士:

  • 中国剩余定理

因为 p p p 不为质数,所以得使用扩展卢卡斯定理( E x t e n d e d   L u c a s , e x L u c a s \rm Extended\ Lucas,exLucas Extended Lucas,exLucas)。

Part 1:中国剩余定理

首先按照 唯一分解定理 p p p 分解质因数:
p = ∏ i = 1 k q i α i p=\prod\limits_{i=1}^{k}q_i^{\alpha_i} p=i=1kqiαi
如果我们能够求出
{ ( n m )   m o d   q 1 α 1 ( n m )   m o d   q 2 α 2 ⋯ ( n m )   m o d   q k α k \begin{cases} \dbinom{n}{m}\bmod q_1^{\alpha_1}\\ \dbinom{n}{m}\bmod q_2^{\alpha_2}\\ \cdots\\ \dbinom{n}{m}\bmod q_k^{\alpha_k} \end{cases} (mn)modq1α1(mn)modq2α2(mn)modqkαk
那么因为 ∀ i ≠ j , gcd ⁡ ( q i α i , q j α j ) = 1 \forall i\ne j,\gcd(q_i^{\alpha_i},q_j^{\alpha_j})=1 i=j,gcd(qiαi,qjαj)=1,所以可以用 CRT 合并。

那么问题就变成了求出 ( n m )   m o d   q i α i \dbinom{n}{m}\bmod q_i^{\alpha_i} (mn)modqiαi

Part 2:移除分子分母中的质因数

( n m ) ≡ n ! m ! ( n − m ) ! ≡ n ! ⋅ inv ⁡ ( m ! ) ⋅ inv ⁡ [ ( n − m ) ! ] ( m o d q α ) \begin{aligned} \dbinom{n}{m} &\equiv \dfrac{n!}{m!(n-m)!}\\ &\equiv n!\cdot \operatorname{inv}(m!)\cdot \operatorname{inv}[(n-m)!] \pmod {q^{\alpha}} \end{aligned} (mn)m!(nm)!n!n!inv(m!)inv[(nm)!](modqα)

m ! , ( n − m ) ! m!,(n-m)! m!,(nm)! q α q^{\alpha} qα 不一定互质,所以不一定存在逆元。

我们将分子和分母中的 q q q 的倍数全部提出来,设 n ! , m ! , ( n − m ) ! n!,m!,(n-m)! n!,m!,(nm)! 分别含 x , y , z x,y,z x,y,z 个质因数 q q q

n ! m ! ( n − m ) ! = n ! q x m ! q y ⋅ ( n − m ) ! q z ⋅ q x − y − z ≡ n ! q x ⋅ inv ⁡ ( m ! q y ) ⋅ inv ⁡ [ ( n − m ) ! q z ] ( m o d q α ) \begin{aligned} \dfrac{n!}{m!(n-m)!} &=\dfrac{\dfrac{n!}{q^x}}{\dfrac{m!}{q^y}\cdot \dfrac{(n-m)!}{q^z}}\cdot q^{x-y-z}\\ &\equiv \dfrac{n!}{q^x}\cdot \operatorname{inv}\left(\dfrac{m!}{q^y}\right)\cdot \operatorname{inv}\left[\dfrac{(n-m)!}{q^z}\right]\pmod {q^{\alpha}} \end{aligned} m!(nm)!n!=qym!qz(nm)!qxn!qxyzqxn!inv(qym!)inv[qz(nm)!](modqα)

这时 m ! q y , ( n − m ) ! q z \dfrac{m!}{q^y},\dfrac{(n-m)!}{q^z} qym!,qz(nm)! 都与 q α q^{\alpha} qα 互质。

Part 3:计算

n ! n! n! 为例:

n ! = ( q × 2 q × ⋯ × ⌊ n q ⌋ q ) × ∏ q ∤ i n i = q ⌊ n q ⌋ × ⌊ n q ⌋ ! × ∏ q ∤ i n i \begin{aligned} n! &=(q\times 2q\times \cdots\times \left\lfloor\dfrac{n}{q}\right\rfloor q)\times \prod\limits_{q\nmid i}^n i\\ &=q^{\left\lfloor\frac{n}{q}\right\rfloor}\times \left\lfloor\dfrac{n}{q}\right\rfloor!\times \prod\limits_{q\nmid i}^n i \end{aligned} n!=(q×2q××qnq)×qini=qqn×qn!×qini
其中 q ⌊ n q ⌋ q^{\left\lfloor\frac{n}{q}\right\rfloor} qqn 可用快速幂直接算, ⌊ n q ⌋ ! \left\lfloor\dfrac{n}{q}\right\rfloor! qn! 可递归求解,后面 ∏ q ∤ i n i \prod\limits_{q\nmid i}^n i qini 就不好算了。

我们发现因为模数是 q α q^{\alpha} qα,又有 x + q α ≡ x ( m o d q α ) x+q^{\alpha}\equiv x\pmod{q^{\alpha}} x+qαx(modqα),所以可以将 q α q^{\alpha} qα 作为一个循环周期,暴力算出 ∏ q ∤ i q α i \prod\limits_{q\nmid i}^{q^{\alpha}}i qiqαi,然后循环实际上有 ⌊ n q α ⌋ \left\lfloor\dfrac{n}{q^{\alpha}}\right\rfloor qαn 个,直接用快速幂。

对于多出来的部分,长度一定小于 q α q^{\alpha} qα,也可以暴力算。

n = 19 , p = 3 , α = 2 n=19,p=3,\alpha=2 n=19,p=3,α=2 为例:
19 ! = 1 × 2 × 3 × 4 × 5 × 6 × 7 × 8 × 9 × 10 × 11 × 12 × 13 × 14 × 15 × 16 × 17 × 18 × 19 = ( 1 × 2 × 4 × 5 × 7 × 8 ) × ( 10 × 11 × 13 × 14 × 16 × 17 ) × 19 × ( 3 × 6 × 9 × 12 × 15 × 18 ) = ( 1 × 2 × 4 × 5 × 7 × 8 ) × ( 10 × 11 × 13 × 14 × 16 × 17 ) × 19 × 3 6 × ( 1 × 2 × 3 × 4 × 5 × 6 ) ≡ ( 1 × 2 × 4 × 5 × 7 × 8 ) 2 × 19 × 3 6 × 6 ! ( m o d 3 2 ) = ∏ 3 ∤ i 19 i × 3 ⌊ 19 3 ⌋ × ⌊ 19 3 ⌋ !   \begin{aligned} 19! &=1\times2\times3\times4\times5\times6\times7\times8\times9\times10\times11\times12\times13\times14\times15\times16\times17\times18\times19\\ &=(1\times2\times4\times5\times7\times8)\times(10\times11\times13\times14\times16\times17)\times19\times(3\times6\times9\times12\times15\times18)\\ &=(1\times2\times4\times5\times7\times8)\times(10\times11\times13\times14\times16\times17)\times19\times3^6\times(1\times2\times3\times4\times5\times6)\\ &\equiv (1\times2\times4\times5\times7\times8)^2\times19\times3^6\times6!\pmod {3^2}\\ &=\prod\limits_{3\nmid i}^{19}i\times 3^{\left\lfloor\frac{19}{3}\right\rfloor}\times \left\lfloor\dfrac{19}{3}\right\rfloor!~ \end{aligned} 19!=1×2×3×4×5×6×7×8×9×10×11×12×13×14×15×16×17×18×19=(1×2×4×5×7×8)×(10×11×13×14×16×17)×19×(3×6×9×12×15×18)=(1×2×4×5×7×8)×(10×11×13×14×16×17)×19×36×(1×2×3×4×5×6)(1×2×4×5×7×8)2×19×36×6!(mod32)=3i19i×3319×319! 
再递归计算 6 !   m o d   3 2 6!\bmod 3^2 6!mod32 即可。

递归部分的代码如下:

ll cal(ll n, ll p, ll pa)
{
	if (!n)
	{
		return 1;
	}
	ll ans = 1;
	for (int i = 1; i <= pa; i++) //循环部分
	{
		if (i % p)
		{
			ans = ans * i % pa;
		}
	}
	ans = qpow(ans, n / pa, pa);
	for (int i = 1; i <= n % pa; i++) //多出部分
	{
		if (i % p)
		{
			ans = ans * i % pa;
		}
	}
	return ans * cal(n / p, p, pa) % pa;
}

注意到这部分其实求的就是 n ! q x \dfrac{n!}{q^x} qxn!

对于 m ! , ( n − m ) ! m!,(n-m)! m!,(nm)! 的处理同理。

Part 4:合并

通过 Part 3 可以求出 n ! q x , m ! q y , ( n − m ) ! q z \dfrac{n!}{q^x},\dfrac{m!}{q^y},\dfrac{(n-m)!}{q^z} qxn!,qym!,qz(nm)!,现在只需要求出 x , y , z x,y,z x,y,z 就可以得到 q x − y − z q^{x-y-z} qxyz 了。

怎么算想必小奥都讲过了吧,比如说
x = ⌊ n q ⌋ + ⌊ n q 2 ⌋ + ⌊ n q 3 ⌋ + ⋯ x=\left\lfloor\dfrac{n}{q}\right\rfloor+\left\lfloor\dfrac{n}{q^2}\right\rfloor+\left\lfloor\dfrac{n}{q^3}\right\rfloor+\cdots x=qn+q2n+q3n+
至此可求出 ( n m )   m o d   q i α i \dbinom{n}{m}\bmod q_i^{\alpha_i} (mn)modqiαi,再结合 Part 1 使用 CRT 合并就完成了求解 ( n m )   m o d   p \dbinom{n}{m}\bmod p (mn)modp 的过程。

Code

//18 = 9 + 9 = 18.
#include <iostream>
#include <cstdio>
#define Debug(x) cout << #x << "=" << x << endl
typedef long long ll;
using namespace std;

ll qpow(ll a, ll b, ll p)
{
	ll base = a, ans = 1;
	while (b)
	{
		if (b & 1)
		{
			ans = ans * base % p;
		}
		base = base * base % p;
		b >>= 1;
	}
	return ans;
}

ll cal(ll n, ll p, ll pa)
{
	if (!n)
	{
		return 1;
	}
	ll ans = 1;
	for (int i = 1; i <= pa; i++)
	{
		if (i % p)
		{
			ans = ans * i % pa;
		}
	}
	ans = qpow(ans, n / pa, pa);
	for (int i = 1; i <= n % pa; i++)
	{
		if (i % p)
		{
			ans = ans * i % pa;
		}
	}
	return ans * cal(n / p, p, pa) % pa;
}

ll cnt_p(ll n, ll m, ll p)
{
	ll cnt = 0;
	for (ll i = p; i <= n; i *= p)
	{
		cnt += n / i;
	}
	for (ll i = p; i <= m; i *= p)
	{
		cnt -= m / i;
	}
	for (ll i = p; i <= n - m; i *= p)
	{
		cnt -= (n - m) / i;
	}
	return cnt;
}

ll x, y;

void exgcd(ll a, ll b)
{
	if (!b)
	{
		x = 1, y = 0;
		return;
	}
	exgcd(b, a % b);
	ll tmp = x;
	x = y;
	y = tmp - a / b * y;
}

ll inv(ll a, ll p)
{
	exgcd(a, p);
	x = (x % p + p) % p;
	return x;
}

ll C(ll n, ll m, ll p, ll pa)
{
	ll a = cal(n, p, pa), b = cal(m, p, pa), c = cal(n - m, p, pa), cnt = cnt_p(n, m, p);
	return a * inv(b, pa) % pa * inv(c, pa) % pa * qpow(p, cnt, pa) % pa;
}

ll a[10], b[10];

ll CRT(int n)
{
	ll m = 1;
	for (int i = 1; i <= n; i++)
	{
		m *= a[i];
	}
	ll ans = 0;
	for (int i = 1; i <= n; i++)
	{
		ll mi = m / a[i];
		ll Mi = inv(mi, a[i]);
		ans = (ans + b[i] * mi % m * Mi % m) % m;
	}
	return ans;
}

ll exLucas(ll n, ll m, ll p)
{
	int k = 0;
	for (ll i = 2; i * i <= p; i++)
	{
		if (p % i == 0)
		{
			a[++k] = 1;
			while (p % i == 0)
			{
				a[k] *= i;
				p /= i;
			}
			b[k] = C(n, m, i, a[k]);
		}
	}
	if (p > 1)
	{
		a[++k] = p;
		b[k] = C(n, m, p, p);
	}
	return CRT(k);
}

int main()
{
	ll n, m, p;
	scanf("%lld%lld%lld", &n, &m, &p);
	printf("%lld\n", exLucas(n, m, p));
	return 0;
}

Complexity

计算 n ! q x   m o d   q α \dfrac{n!}{q^x}\bmod q^{\alpha} qxn!modqα 的时间为 O ( q α log ⁡ n ) O(q^{\alpha}\log n) O(qαlogn)

计算 x x x 的时间为 O ( log ⁡ n ) O(\log n) O(logn)

所以计算 ( n m )   m o d   q α \dbinom{n}{m}\bmod q^{\alpha} (mn)modqα 的时间为 O ( q α log ⁡ n ) O(q^{\alpha}\log n) O(qαlogn)

整个预处理部分就是 O ( p + ∑ i = 1 k q i α i log ⁡ n ) O(\sqrt{p}+\sum\limits_{i=1}^k q_i^{\alpha_i}\log n) O(p +i=1kqiαilogn)

CRT 部分是 O ( k log ⁡ ∏ i = 1 k q i α i ) = O ( k log ⁡ p ) O(k\log \prod\limits_{i=1}^k q_i^{\alpha_i})=O(k\log p) O(klogi=1kqiαi)=O(klogp) 的。

综上,exLucas 的时间复杂度为 O ( p + ∑ i = 1 k q i α i log ⁡ n + k log ⁡ p ) ∼ O ( p log ⁡ n ) O(\sqrt{p}+\sum\limits_{i=1}^k q_i^{\alpha_i} \log n+k\log p)\sim O(p\log n) O(p +i=1kqiαilogn+klogp)O(plogn)

Problems

模板

P4720 【模板】扩展卢卡斯定理/exLucas

模板 + 乘法原理

P2183 [国家集训队]礼物

答案为 ( n w 1 ) × ( n − w 1 w 2 ) × ( n − w 1 − w 2 w 3 ) × ⋯   m o d   P \dbinom{n}{w_1}\times \dbinom{n-w_1}{w_2}\times \dbinom{n-w_1-w_2}{w_3}\times \cdots\bmod P (w1n)×(w2nw1)×(w3nw1w2)×modP

References

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值