1. 程式人生 > 其它 >【數學】盧卡斯定理

【數學】盧卡斯定理

給定 \(n,m,p\),其中 \(n,m\) 較大,\(p\) 為質數且不是很大,求

\[\dbinom{n}{m}\bmod p \]

\(\rm Lucas\) 定理

\[\dbinom{n}{m}\equiv\dbinom{\left\lfloor\frac{n}{p}\right\rfloor}{\left\lfloor\frac{m}{p}\right\rfloor}\cdot \dbinom{n\bmod p}{m\bmod p}\pmod p(p 為質數) \]

引理 \(1\)

觀察

\[\dbinom{p}{n}\equiv\dfrac{p!}{(p-n)!\cdot n!}\pmod p \]

分子含有質因數 \(p\)

,所以當分母不含質因數 \(p\) 時答案為 \(0\)

否則,僅當 \(n=0\)\(n=p\) 時分母也含有質因數 \(p\),答案為 \(\dfrac{p!}{p!\cdot 0!}=1\)

引理 \(2\)

考慮這樣一個式子

\[(a+b)^p \]

根據二項式定理,這個就是

\[\sum\limits_{i=0}^{p}\dbinom{p}{i}a^i b^{p-i} \]

由引理 \(1\),只有 \(i=0\)\(i=p\)\(\dbinom{p}{i}\) 在模 \(p\) 的意義下值為 \(1\),所以

\[\begin{aligned} (a+b)^p &\equiv a^0 b^p+a^p b^0\\ &\equiv a^p+b^p\pmod p \end{aligned} \]

那麼

\[(ax+by)^p\equiv a^p x^p+b^p y^p\pmod p \]

由費馬小定理得

\(a^p x^p+b^p y^p\equiv a x^p+b y^p\pmod p\)

就是說可以直接把指數 \(p\)​ 往裡乘。

證明:

\((x+1)^n\) 中的項 \(x^m\) 的係數模 \(p\),根據二項式定理就是 \(\dbinom{n}{m}\bmod p\)\(\quad(1)\)

又根據引理 \(2\)

\[\begin{aligned} (x+1)^n &\equiv (x+1)^{p\left\lfloor\frac{n}{p}\right\rfloor}(x+1)^{n\bmod p}\\ &\equiv (x^p+1^p)^{\left\lfloor\frac{n}{p}\right\rfloor}(x+1)^{n\bmod p}\\ &\equiv (x^p+1)^{\left\lfloor\frac{n}{p}\right\rfloor}(x+1)^{n\bmod p}\pmod p \end{aligned} \]

我們發現:

  1. \((x^p+1)^{\left\lfloor\frac{n}{p}\right\rfloor}\) 中的各項的次數均為 \(p\) 的倍數。

  2. \((x+1)^{n\bmod p}\) 中的各項的次數最多為 \(p-1\)

注意到第 \(2\) 條,次數最多隻能到 \(p-1\),所以要想得到 \(x^m\),只有一種方法:令 \(m=pq+r(r<p)\),則在 \((x^p+1)^{\left\lfloor\frac{n}{p}\right\rfloor}\) 中取到 \(q\)(即 \(\left\lfloor\frac{m}{p}\right\rfloor\))個 \(x^p\),然後在 \((x+1)^{n\bmod p}\) 取到 \(r\)(即 \(m\bmod p\))個 \(x\)

方法數為 \(\dbinom{\left\lfloor\frac{n}{p}\right\rfloor}{q}\cdot\dbinom{n\bmod p}{r}\equiv\dbinom{\left\lfloor\frac{n}{p}\right\rfloor}{\left\lfloor\frac{m}{p}\right\rfloor}\cdot\dbinom{n\bmod p}{m\bmod p}\pmod p\quad(2)\)

\((1)(2)\) 可得

\[\dbinom{n}{m}\equiv \dbinom{\left\lfloor\frac{n}{p}\right\rfloor}{\left\lfloor\frac{m}{p}\right\rfloor}\cdot \dbinom{n\bmod p}{m\bmod p}\pmod p \]

證畢。

P3807 【模板】盧卡斯定理/Lucas 定理

預處理處 \(\forall i\in[0,p)\)\(i!\)\(inv(i!)\)。然後對於單個詢問,\(\dbinom{\left\lfloor\frac{n}{p}\right\rfloor}{\left\lfloor\frac{m}{p}\right\rfloor}\) 部分遞迴去跑,因為 \(p\ge 2\),所以是 \(\log n\) 的,\(\dbinom{n\bmod p}{m\bmod p}\) 部分就是預處理的。

時間複雜度為 \(\mathcal{O}(p+T\log n)\),其中 \(T\) 為詢問次數。

可以發現瓶頸在於線性的預處理,所以 \(p\) 不能太大。

\(\text{Code}\)

//18 = 9 + 9 = 18.
#include <iostream>
#include <cstdio>
typedef long long ll;
using namespace std;

const int MAXN = 1e5 + 5;


int p;

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

int inv(int a)
{
	return qpow(a, p - 2);
}

int fac[MAXN], inv_fac[MAXN];

void init()
{
	fac[0] = 1;
	for (int i = 1; i < p; i++)
	{
		fac[i] = (ll)fac[i - 1] * i % p;
	}
	inv_fac[p - 1] = inv(fac[p - 1]);
	for (int i = p - 2; i >= 0; i--)
	{
		inv_fac[i] = (ll)inv_fac[i + 1] * (i + 1) % p;
	}
}

int C(int n, int m)
{
	if (m > n)
	{
		return 0;
	}
	return (ll)fac[n] * inv_fac[n - m] % p * inv_fac[m] % p;
}

int Lucas(int n, int m)
{
	if (!m)
	{
		return 1;
	}
	return (ll)Lucas(n / p, m / p) * C(n % p, m % p) % p;
}

int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
	{
		int n, m;
		scanf("%d%d%d", &n, &m, &p);
		init();
		printf("%d\n", Lucas(n + m, n));
	}
	return 0;
}