【數學】盧卡斯定理
給定 \(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} \]我們發現:
\((x^p+1)^{\left\lfloor\frac{n}{p}\right\rfloor}\) 中的各項的次數均為 \(p\) 的倍數。
\((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 \]證畢。
預處理處 \(\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;
}