1. 程式人生 > 其它 >【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)做數論全家桶古代豬文了!
繼續努力……