卢卡斯定理的详解和线性求解逆元(含题目)

119 篇文章 1 订阅
113 篇文章 1 订阅

【卢卡斯定理】

卢卡斯定理是用来求解: Cmn+m C n + m m %mod的值,而mod是一个质数。

我也是看了很长时间的讲解才看懂的(感觉好弱啊~~~)

这张图是我认为讲解最全的,(可能一时看不懂,我再补充一下)。
这里写图片描述

首先,你要看懂

(1+x)p1+xp%p ( 1 + x ) p ≡ 1 + x p % p

并推出
(1+x)a(1+x)a0(1+xp)a1((1+x)pk)ak%p ( 1 + x ) a ≡ ( 1 + x ) a 0 ∗ ( 1 + x p ) a 1 ∗ • • • ∗ ( ( 1 + x ) p k ) a k % p

以上都不难,最难的是最后一步,我一直没有想明白,想了很久才明白的(太菜了)。
就是左右两边的 xb x b 的项系数是相同的,
左边是
Cbaxb C a b ∗ x b

右边是,每一项提取一个式子
Cb0a0xb0Cb1a1xpb1Cb2a2xp2b2Cbkakxpkbk C a 0 b 0 x b 0 ∗ C a 1 b 1 x p b 1 ∗ C a 2 b 2 x p 2 b 2 ∗ • • • ∗ C a k b k x p k b k
=Cb0a0Cb1a1Cb2a2Cbkakxb0+pb1+p2b2++pkbk = C a 0 b 0 ∗ C a 1 b 1 ∗ C a 2 b 2 ∗ • • • ∗ C a k b k ∗ x b 0 + p b 1 + p 2 b 2 + • • • + p k b k

b0+pb1+p2b2++pkbk b 0 + p b 1 + p 2 b 2 + • • • + p k b k 是p进制的b,所以是 xb x b 所以
Cba=Cb0a0Cb1a1Cb2a2Cbkak C a b = C a 0 b 0 ∗ C a 1 b 1 ∗ C a 2 b 2 ∗ • • • ∗ C a k b k

证明完毕了!

也可以用递归的方法来写: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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值