zoukankan      html  css  js  c++  java
  • lucas定理

    Update:

    代码已更新,之前的代码算数时会溢出 QAQ

    应用:

    Lucas定理的应用范围在于大的组合数取模。简而言之,就是用来求 c(n,m) mod p,p为素数的值

    定义:

    C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p

    求解上式时,递归出口为 m = 0 时返回 1.

    证明:

    下面附上Lucas定理的一种证明,见下图,参考冯志刚《初等数论》第37页。

     对于证明过程的一些解释:

    update:上面第三条的C(a,b)应该是C(b,a)。

    代码实现:

    typedef long long LL;
    const LL mod = 1e9+7;
    LL quick_pow(LL x, LL n, LL p)// 快速幂求x^n mod p 的结果
    {
        if(n==0)
            return 1;
        if(n==1)
            return x%p;
        LL ans = 1;
        LL tmp = x%p;
        while(n)
        {
            if(n&1)
            {
                ans = (ans*tmp)%p;
            }
            tmp = tmp*tmp%p;
            n>>=1;
        }
        return ans%p;
    }
    LL inv(LL b,LL p) //求数 b mod p 的逆元
    {
        return quick_pow(b,p-2,p);
    }
    LL C(LL n,LL m,LL p)//组合数取模
    {
        if(m==0|| m== n)
            return 1;
        if(m==1||m==n-1)
            return n%p;
            m = min(m,n-m);
        LL up = 1,down = 1;
        for(LL i = n-m+1;i<=n;i++)
            up=(up*i)%p;
        for(LL i = 1;i<=m;i++)
            down=(down*i)%p;
        up%=p;
        down%=p;
        return (up*(inv(down,p)%p))%p;
    }
    LL lucas(LL n,LL m,LL p)//递归lucas函数
    {
        if(m==0)
            return 1;
        return lucas(n/p,m/p,p)*C(n%p,m%p,p)%p;
    }

    如果对求逆元不是十分了解,欢迎去我的上一篇博客去看看。

    如果还有疑问,欢迎在评论区留言/

  • 相关阅读:
    面向对象之继承
    面向对象之封装
    进程相关(一)
    面向对象之反射,元类
    实现效果从中间变大
    如何扒一个网站
    java例程练习(引用类型数据的排序和查找)[外篇]
    java例程练习(Iterator)
    java例程练习(增强的for循环)
    java例程练习(Map接口及自动打包、解包)
  • 原文地址:https://www.cnblogs.com/baihualiaoluan/p/11257478.html
Copyright © 2011-2022 走看看