Lucas定理入门
前置结论
如果 \(p\) 为素数,有以下结论:
-
\(a^p \equiv a \pmod p\)
即费马小定理 -
\[C_{p}^i \equiv \begin{cases} 1 & i=0 或者 i=p \\ 0 & 其他情况 \end{cases} \pmod p \]
证明可以展开
- \((a+b)^p \equiv a^p + b^p \pmod p\)
证明1:用结论1\[\begin{aligned} (a+b)^p &\equiv a+b \\ &\equiv a^p + b^p \pmod p \end{aligned} \]证明2:用结论2 和 二项式定理\[\begin{aligned} (a+b)^p &\equiv \sum_{i=0}^{p} C_{p}^{i} \times a^i \times b^{p-i} \\ &\equiv a^p + b^p \pmod p \end{aligned} \]
Lucas定理
内容
$ C_{n}^{m} \equiv C_{\lfloor \frac{n}{p} \rfloor} ^{\lfloor \frac{m}{p} \rfloor} \cdot C_{n \bmod p}^{m \bmod p} \pmod p \text{ p 是 质数}$
用途
当质数 \(p\) 较小时,求解组合数在模意义下的值
证明
由二项式定理得:\(C_n^m\) 等于 \((x+1)^n\) 展开后 \(x^m\) 的系数
所以 \((x+1)^n\) 展开后 \(x^m\) 的系数 = \(\sum (x^p + 1)^{\lfloor \frac{n}{p} \rfloor}\)展开后\(x^{m-r}\)的系数 \(\times (x+1)^{n \bmod p}\)展开后 \(x^r\) 的系数
容易得到 \(r \le n\bmod p < p\) 并且 \(p \mid (m-r)\) , 也就是说 \(m\) 可以写成 \(m=k \times p + r , r<p\) 的形式,根据带余除法可知这种表示是唯一的,即只有一个唯一的 \(r\) 和 \(k\) ,其中 $r = m \bmod p,k = \lfloor \frac{m}{p} \rfloor $
所以$ C_{n}^{m} \equiv C_{\lfloor \frac{n}{p} \rfloor} ^{\lfloor \frac{m}{p} \rfloor} \cdot C_{n \bmod p}^{m \bmod p} \pmod p$
代码实现
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
inline int read(){
int w = 1, s = 0;
char c = getchar();
for (; c < '0' || c > '9'; w *= (c == '-') ? -1 : 1, c = getchar());
for (; c >= '0' && c <= '9'; s = 10 * s + (c - '0'), c = getchar());
return s * w;
}
int T,n,m,p;
int fac[N],inv[N],q[N];
int C(int n,int m){
if(m>n) return 0;
return fac[n]*q[m]%p*q[n-m]%p;
}
int Lucas(int n,int m){
if(!m) return 1;
return C(n%p,m%p)*Lucas(n/p,m/p)%p;
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
T=read();
while(T--){
n=read(),m=read(),p=read();
fac[0]=1;
for(int i=1;i<p;i++) fac[i]=fac[i-1]*i%p;
inv[1]=1;
for(int i=2;i<p;i++) inv[i]=inv[p%i]*(p-p/i)%p;
q[0]=1;
for(int i=1;i<p;i++) q[i]=q[i-1]*inv[i]%p;
n=n+m;
printf("%lld\n",Lucas(n,m));
}
return 0;
}
拓展
考虑 \(m,n\) 在 \(p\) 进制下的表示,就会发现 \(C^m_n\) 就等于 \(m,n\) 在 \(p\) 进制下每一位对应的组合数的乘积( \(\bmod\)操作就是取最后一位,\(\lfloor \rfloor\)就是左移一位 ) 。
特殊的,当 \(p=2\) 时,组合数有值当且仅当 \(m\) 是 \(n\) 的子集
此时就很高位前缀和 (关于高位前缀和的知识看这)