其他分享
首页 > 其他分享> > 【Coel.学习笔记】卢卡斯定理(Lucas Theorem)

【Coel.学习笔记】卢卡斯定理(Lucas Theorem)

作者:互联网

题前碎语

这周要开家长会,回去就要把自选科目选定了。
当然选课对我来说没什么(物生地YYDS!),但是选课就意味着要分班,就要和原本实验班的同学说再见了……
\(qwq\)……

笔记内容

本笔记含有卢卡斯定理。

卢卡斯定理

卢卡斯定理(\(Lucas\) \(Theorem\),又名\(Lucas\)定理)是一种用于求解大组合数取模的定理,能够在\(O(klogn)\)的时间复杂度下求解大组合数取模,但必须保证取模数为质数。
卢卡斯定理的基本形式为:

\[C^m_n=C^{m\mod n}_{n\mod p}*C^{m/p}_{m/p} \]

即把\(n\)与\(m\)分解为\(p\)进制数,对该进制每一位求解组合数并相加。
因此,这也要求\(p\)不能太大(小于\(10^5\))。
在实际实现中可以写成递归的形式,递归边界即为\(C^0_n=1\)。
代码如下:洛谷传送门

#include<cstdio>
#include<cctype>
#define maxn 100050
long long n,m,p,T;
long long read()
{
	long long x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(isdigit(ch))
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	return x*f;
}
long long qpow(long long a,long long b,long long p)
{
    long long sum=1;
    while(b)
    {
        if(b&1)sum=sum*a%p;
        a=a*a%p;
        b>>=1;
    }
    return sum;
}
long long C(long long n,long long m,long long p)
{
	if(m>n)return 0;
	long long a=1,b=1;
	for(int i=n-m+1;i<=n;i++)
		a=a*i%p;
	for(int i=2;i<=m;i++)
		b=b*i%p;
	return a*qpow(b,p-2,p)%p;//考虑到p必定是质数,所以用费马小定理求逆元
}
long long Lucas_Theorem(long long n,long long m,long long p)
{
	return m?(C(n%p,m%p,p)*Lucas_Theorem(n/p,m/p,p))%p:1;
}
int main()
{
	T=read();
	while(T--)
	{
		n=read(),m=read(),p=read();
		printf("%lld\n",Lucas_Theorem(n+m,m,p));
	}
	return 0;
}

题后闲话

没什么想说的(
学完卢卡斯定理之后再加一个扩展欧拉定理就能召唤神龙(bushi)做数论全家桶古代猪文了!
继续努力……

标签:ch,return,Lucas,定理,Coel,long,Theorem,卢卡斯,sum
来源: https://www.cnblogs.com/Coel-Flannette/p/15724794.html