Lucas定理也是好的。
什么是Lucas定理
这是一个有助于分解组合数来求解的定理,适合模数小,数字大的问题。
有质数 ,对于,如果,有
由此可以分解成较小的问题求解。
证明Lucas定理
这个证明利用了二项式定理的思路,前所未闻,真的很有趣。
根据二项式定理可以得到 中的系数为。
我们用这一点作为突破口,对于,我们有
然后有一个很有意思的东西
为什么呢?将式子拆开后,显然除了第一项与最后一项,其他项是的倍数,自然就会抹掉了。
继续进行推导,我们有
于是右边的式子拆开可以得到
我们要求的系数,也就是的系数。
由于,所以只能让负责了,当时符合条件,此时系数为。
剩下部分由负责,当时符合条件,此时系数为。
因此 的系数为,前文已知根据二项式定理的系数为,我们得到
由此,完成了Lucas定理的证明。
Lucas定理求解组合数的C++实现
代码上没什么难点,首先基础的组合数求解还是要有的,也就是我们需要预处理阶乘逆元,然后使用Lucas将组合数拆开再用基础的组合数求解即可。
long long ksm(long long x,long long y)
{
long long sum=1;
while(y)
{
if(y&1)
{
sum*=x;
sum%=mod;
}
x*=x;
x%=mod;
y>>=1;
}
return sum;
}
long long C(long long n,long long m)
{
if(m>n)return 0;
if(m==0||n==m)return 1;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
long long lucas(long long n,long long m)
{
if(m>n)return 0;
if(n<mod)return C(n,m);
return lucas(n/mod,m/mod)*lucas(n%mod,m%mod)%mod;
}
void init()
{
fac[0]=1;
for(int i=1;i<=mod-1;i++)
{
fac[i]=fac[i-1]*i%mod;
}
inv[mod-1]=ksm(fac[mod-1],mod-2);
for(int i=mod-2;i>=0;i--)
{
inv[i]=inv[i+1]*(i+1)%mod;
}
}