【Coel.学习笔记】卢卡斯定理(Lucas Theorem)
作者:互联网
题前碎语
这周要开家长会,回去就要把自选科目选定了。
当然选课对我来说没什么(物生地YYDS!),但是选课就意味着要分班,就要和原本实验班的同学说再见了……
\(qwq\)……
笔记内容
本笔记含有卢卡斯定理。
卢卡斯定理
卢卡斯定理(\(Lucas\) \(Theorem\),又名\(Lucas\)定理)是一种用于求解大组合数取模的定理,能够在\(O(klogn)\)的时间复杂度下求解大组合数取模,但必须保证取模数为质数。
卢卡斯定理的基本形式为:
即把\(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