• 卢卡斯定理&扩展卢卡斯(Lucas)


    卢卡斯定理&拓展卢卡斯#

    部分资料来自:

    1.https://blog.csdn.net/qq_40679299/article/details/80489761

    2.https://www.luogu.com.cn/problemnew/solution/P3807

    本文章中,排列组合C(n,m)表示,n中取m个,不考虑顺序


    前置芝士~:

    1)乘法逆元

    如果ax≡1 (mod p),且gcd(a,p)=1(a与p互质),则称a关于模p的乘法逆元为x

    2)费马小定理:

    a ^(p-1)≡1(mod p)(其中a与p互质)

    3)扩展欧几里得

    已知整数a、b,扩展欧几里得算法可以在求得a、b的最大公约数的同时,能找到整数x、y(其中一个很可能是负数),使它们满足贝祖等式ax + by = gcd(a, b)

    求逆元一般可以使用费马小定理或扩展欧几里得实现。


    卢卡斯定理

    那么我们现在开始正式介绍lucas定理。

    适用范围

    所求C(n,m)%mod,mod一般是质数,并且n,m相对而言比较大,而且如果mod显然大于n,m,那就没必要写lucas,光求逆元足够了

    像下面这样的取n,m,p的值就比较好地适用lucas

    40118 16827 2521

    18506 3902 883

    核心思想

    我们在组合数学当中要计算C(n,m)的时候往往数据比较大,需要进行取模操作。

    由于含有除法的计算,不能直接取模,否则会出现像下面的问题:

    你比如3 * 5 * 7 / 5 % 4

    你如果正常计算答案是1,而如果你先算出15,取模成3,再算21,取模成1,那么还有个5没除,那怎么办?

    显然,这样处理忽视了一个问题,即在前面取走的k * 4并没有被/5处理,而这一部分一旦/5后,很可能不再能被4整除

    而Lucas定理正是基于此,将除法通过求逆元的方式,将其转化成乘法,使得取模操作不会产生上述的后果

    F / A === 所求量 (mod C)

    如果存在 A * X === 1 (mod C)

    那么2边同时乘起来,得到 F * X === 所求量 (mod C)

    成立条件

    (1) 模方程 A * X === 1(mod C) 存在解

    (2) A | F (F % A == 0)

    这样除法就巧妙地变成了乘法

    定理描述

    冯志刚《初等数论》版及证明:

    洛谷大佬证明


    扩展卢卡斯定理##


    洛谷P3807##

    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long int LL;
    LL p;
    LL min(LL a,LL b)
    {
        return a<b?a:b;
    }
    
    LL up(LL k,LL num)
    {
        LL awsl=1;
        while(k)
        {
            if(k&1)awsl=(awsl*num)%p;
            k/=2;
            num=(num*num)%p;
        }
        return awsl%p;
    }
    LL getx(LL a)
    {
    if(a==1)return 1;
        return up(p-2,a);
    }
    LL c(LL m,LL n)
    {
        if(m<n)return 0;
        n=min(n,m-n);
        LL ans=1;
        for(int i=1;i<=n;i++)
        {
            ans=ans*(m+1-i)%p*getx(i)%p;
        }
        return ans;
    }
    LL Lucas(LL m,LL n)
    {
        LL ans=1;
        LL cur=1;
        while(cur<=m||cur<=n)cur*=p;
        while(cur)
        {
            ans*=c(m/cur,n/cur);
            m=m%cur;
            n=n%cur;
            cur/=p;
        }
        return ans%p;
    }
    void solve()
    {
        LL n,m;
        cin>>n>>m>>p;
        cout<<Lucas(m+n,n)<<endl;
    }
    int main()
    {
        int t;
        cin>>t;
        for(int i=0;i<t;i++)
        {
            solve();
        }
        return 0;
    }
  • 相关阅读:
    中值滤波与图像锐化
    空间域图像增强
    图像的几何变换
    Fourier分析应用
    Gale-Shapley算法
    有理数与无限循环小数
    线性可分支持向量机
    拉格朗日乘子法+KKT条件
    点到平面的距离
    BP神经网络
  • 原文地址:https://www.cnblogs.com/et3-tsy/p/12499280.html
Copyright © 2020-2023  润新知