• Lucas卢卡斯定理(学习笔记)


    Lucas定理是用来求$C(n,m) mod $ p,p为质数

    若P是质数,则对于任意整数1<=m<=n,有:

    (C^m_n≡C^{m mod p}_{n mod p}*C^{m/p}_{n/p}(mod p))

    也就是

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

    也就是

    (Lucas(n,m)mod p=C(n mod p,m mod p)*Lucas(n/p,m/p)mod p)

    从这个公式我们可以看出我们需要求解的东西有:

    1 组合数C(n,m)

    而组合数公式(C^m_n=n!/(m!*(n-m)!)),所以

    2 阶乘(线性递推)

    由于p是素数,根据费马小定理,(m!*(n - m)!)关于p的逆元就是(m!*(n - m)!)(p-2)次方,所以

    3 逆元(线性递推)

    4 快速幂

    是不是要求解的东西比较多啊,但都是模板;

    P3807 【模板】卢卡斯定理

    给定(n,m,p(1le n,m,ple 10^5))

    (C_{n+m}^m) (mod) p,保证P为prime,C表示组合数;

    这就是lucas定理的模板题,没有什么分析的了,把几个模板打上去就行了;

    只有核心模板的代码

    LL quickpow(LL a,int b){
        LL cnt=1;
        while(b){
        	if(b&1) cnt=cnt*a%p;
        	a=a*a%p;
        	b=b>>1;
        }
        return cnt;
    }//快速幂
    LL C(int a,int b){
        if(a<0||b<0||a<b) return 0;
        return 1ll*jc[a]*ny[b]%p*ny[a-b]%p;
    }//组合数,jc[]表示阶乘,ny[]表示逆元
    LL lucas(int a,int b){
        if(a+b==0) return 1;
        return 1ll*C(a%p,b%p)*lucas(a/p,b/p)%p;
    }//卢卡斯定理
    int main(){
        T=read();
        while(T--){
        	n=read();m=read();p=read();
        	jc[0]=ny[0]=1;
    //线性递推初始化
        	for(LL i=1;i<=p-1;i++)
            	jc[i]=jc[i-1]*i%p;
    //求1到p-1的阶乘
        	ny[p-1]=quickpow(jc[p-1],p-2);
    //求p-1的逆元
        	for(LL i=p-2;i;i--)
            	ny[i]=ny[i+1]*(i+1)%p;
    //线性递推求p-2到1的逆元
        	printf("%lld
    ",lucas(m+n,m));
        }
        return 0;
    }
    
    
  • 相关阅读:
    Mac小知识点
    UIScrollView直接在StoryBoard中拖控件
    iOS小工具
    iOS设备信息
    Android Studio stuck on “Gradle: resolve dependancies '_debugCompile'” or 'detachedConfiguration1'
    iOS开发插件集
    Include guards
    oc单例
    Java反射中与自动装箱有关的坑及其解决方案
    ByxAOP——简易AOP框架
  • 原文地址:https://www.cnblogs.com/PPXppx/p/9898506.html
Copyright © 2020-2023  润新知