盧卡斯定理的詳解和線性求解逆元(含題目)

【盧卡斯定理】

盧卡斯定理是用來求解:Cn+mm %mod的值,而mod是一個質數。

我也是看了很長時間的講解纔看懂的(感覺好弱啊~~~)

這張圖是我認爲講解最全的,(可能一時看不懂,我再補充一下)。
這裏寫圖片描述

首先,你要看懂

(1+x)p1+xp%p

並推出
(1+x)a(1+x)a0(1+xp)a1((1+x)pk)ak%p

以上都不難,最難的是最後一步,我一直沒有想明白,想了很久才明白的(太菜了)。
就是左右兩邊的xb 的項係數是相同的,
左邊是
Cabxb

右邊是,每一項提取一個式子
Ca0b0xb0Ca1b1xpb1Ca2b2xp2b2Cakbkxpkbk
=Ca0b0Ca1b1Ca2b2Cakbkxb0+pb1+p2b2++pkbk

b0+pb1+p2b2++pkbk 是p進制的b,所以是xb 所以
Cab=Ca0b0Ca1b1Ca2b2Cakbk

證明完畢了!

也可以用遞歸的方法來寫: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;
}
發佈了186 篇原創文章 · 獲贊 14 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章