【盧卡斯定理】
盧卡斯定理是用來求解: %mod的值,而mod是一個質數。
我也是看了很長時間的講解纔看懂的(感覺好弱啊~~~)
這張圖是我認爲講解最全的,(可能一時看不懂,我再補充一下)。
首先,你要看懂
並推出
以上都不難,最難的是最後一步,我一直沒有想明白,想了很久才明白的(太菜了)。
就是左右兩邊的 的項係數是相同的,
左邊是
右邊是,每一項提取一個式子
而 是p進制的b,所以是 所以
證明完畢了!
也可以用遞歸的方法來寫:Lucas(a,b)=Lucas(n%p,m%p)*Lucas(n/p,m/p)%p;
繼續對Lucas(n/p,m/p)遞歸即可。
【線性求解逆元】
這個博客講解的很清楚了:線性求解逆元
求解n以內的逆元,時間複雜度O(n)
設 t=M/i , k=M%i;
inv數組記錄的就是i的逆元。
下面是一道例題:
盧卡斯定理
代碼:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+9;
ll factorial[maxn];//記錄階乘
ll inelement[maxn];//記錄,先記錄每個數的逆元,再記錄階乘的逆元
ll lucas(int n,int m,int mod)
{
if(n<m)
return 0;
else if(n<mod)
return factorial[n]*inelement[m]*inelement[n-m]%mod;
else return lucas(n%mod,m%mod,mod)*lucas(n/mod,m/mod,mod)%mod;
}
int main()
{
int t,n,m,mod;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&mod);
factorial[0]=factorial[1]=inelement[0]=inelement[1]=1;
//階乘
for(int i=2;i<=m+n;i++)
{
factorial[i]=factorial[i-1]*i%mod;
}
//逆元,先先求每一個數的逆元,線性求解
for(int i=2;i<=m+n;i++)
{
inelement[i]=(mod-mod/i)*inelement[mod%i]%mod;
}
//求階乘的逆元
for(int i=2;i<=m+n;i++)
{
inelement[i]=inelement[i-1]*inelement[i]%mod;
}
printf("%lld\n",lucas(n+m,m,mod));
}
return 0;
}