卢卡斯定理
众所周知,lucas定理为:
\(C^m_n\bmod p=C^{m/p}_{n/p}* C^{m\%p}_{n\%p}\bmod p\)(p为质数)
理解一下的话,可以认为是将n,m转为p进制,之后按位取组合数,最后乘起来
就好了。具体实现时只需要写个递归函数。
简单易懂,那本文就到此结束了。
举个栗子
\(C^7_8\bmod 2\)
第一步:
将1和3转化为p(2)进制:\(7=0111, 8=1000\)。
第二步:
求出按位的组合数即 \(C^0_1\)、\(C^0_1*3\)
最后一步:
算出ans即 \(\prod^p_1\)(刚刚求得组合数)
这样就轻松的算出0了23333
具体实现的可以使用递归函数,还是很好写的。
int lucas(int nn,int mm)
{
if(!mm) return 1;
return (lucas(nn/p,mm/p)*C(nn%p,mm%p))%p;
}
注意求得时候需要用一下逆元(不用的童鞋请转乘法逆元)
但为什么这定理是对的呢(卢卡斯知道)
我们来证明一下:
首先设 \(n=ap+b,m=cp+d ( a=\lfloor n/p\rfloor,c=\lfloor m/p\rfloor\));
然后来看一个二项式在质数模意义下的小性质: \((1+x)^p=1+x^p\); ( 证明很容易,通过费马小定理两边都可以变成1+x)。
然后我们从二项式的角度思考(假定所有操作在模p意义下进行):
\((1+x)^n=(1+x)^{ap}*(1+x)^b=(1+x^p)^a*(1+x)^b=(\sum^a_{i=0}C^i_a*x^{pi})*(\sum^b_{j=0}C^j_b*x^j)\)
(用到了基本的二项式定理)
之后可以很natural的发现\(x^m\)前的系数为\(C^m_n\)。
\(C^m_n*x^m=C^c_a*x^{cp}*C^d_b*x^d\)
化简一下:\(C^m_n=C^c_a*C^d_b\)
\(C^m_n=C^{m/p}_{n/p}*C^{m\%p}_{n\%p}\)
证毕
接下来便是代码环节了
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,p;
int jc[210000],ni[210000];
int ksm(int a,int b)
{
int tmp=1;
while(b)
{
if(b&1) tmp=(tmp*a)%p;
a=(a*a)%p;
b>>=1;
}
return tmp;
}
int inv(int x)
{
return ksm(x,p-2);
}
int C(int a,int b)
{
if(a<b) return 0;
return (jc[a]*inv(jc[b])%p*inv(jc[a-b]))%p;
}
int lucas(int nn,int mm)
{
// assert(nn!=0);
if(!mm) return 1;
return (lucas(nn/p,mm/p)*C(nn%p,mm%p))%p;
}
signed main()
{
int T;
cin>>T;
while(T--)
{
scanf("%lld%lld%lld",&n,&m,&p);
n=n+m;
jc[0]=1;
for(int i=1;i<=n;i++) jc[i]=(jc[i-1]*i)%p;
printf("%lld\n",lucas(n,m));
}
}

浙公网安备 33010602011771号