• [学习笔记]Lucas定理


    Lucas卢卡斯定理

    一.什么是lucas定理

    ​ lucas定理是用来解决组合数取模问题的,即求解

    [C_n^mpmod{p} ]

    的算法。前提是P为质数。

    二.定理本身

    ​ lucas定理长这个样子

    [Lucas(n,m,p)=C_{n\%p}^{m\%p}*Lucas(frac{n}{p},frac{m}{p},p) ]

    长着一副很好看的面孔呢~,取了模以后就直接用逆元进行运算就好。

    三.n%p<m%p

    ​ 由于有取模,我们会有几个特殊的情况。n<m便是其中的一种。很显然的由于n<m,在组合数意义上是不成立的,所以说我们应该是输出0,所以整个Lucas的值也为零,但是这样是正确的吗?显然是的。

    ​ 为了证明他的正确性,我们首先保证一开始我们要求解的问题有解,即(ngeq m),记

    [egin{align} &n=k_n*p+r_n\ &m=k_m*p+r_m\ ecause& r_n<r_m,ngeq m \ herefore& n-m>p\ ecause&C_n^m=frac{n!}{(n-m)!m!} end{align} ]

    所以在(n-m)~n或m~n之间必定有一个P的倍数没有被约掉,所以mod P=0

    四.非递归形式

    ​ 当我们看到%p,/p的时候,完全可以换角度去思考这个东西,不断地取余又除,相当于是在不断取出P进制下的最后一位,(我们假装n,m是一个P进制的数),所以说Lucas定理是可以用非递归的写法的。

    ​ 下面挂一道Luogu的模板

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    ll n,m,p;
    ll inv[100005]={0,1},q1[100005]={1,1},q2[100005]={1,1};
    ll ready(ll mod){
    	for(int i=2;i<mod;++i){
    		q1[i]=(q1[i-1]*i)%mod;
    		inv[i]=((p-p/i)*inv[p%i]+mod)%mod;
    		q2[i]=(q2[i-1]*inv[i]+mod)%mod;
    	}
    }
    ll C(ll a,ll b,ll mod){
    	return (q1[a]*q2[a-b]%mod)*q2[b]%mod;
    }
    ll Lucas(ll a,ll b,ll mod){
    	ll res=1;
    	while(a&&b){
    		int ma=a%mod,mb=b%mod;
    		if(ma<mb)return 0;
    		res*=C(ma,mb,mod);
    		res%=mod;
    		a/=mod,b/=mod;
    	}
    	return res;
    }
    ll t;
    int main(){
    	cin>>t;
    	while(t--){
    		cin>>n>>m>>p;
    		ready(p);
    		cout<<Lucas(n+m,n,p)<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    线程(java课堂笔记)
    java中的各种流(老师的有道云笔记)
    面向对象(java菜鸟的课堂笔记)
    泛型(java菜鸟的课堂笔记)
    我做的第一个程序(菜鸟的java课堂笔记)
    java中的一些规则(菜鸟的课堂笔记)
    一位菜鸟的java 最基础笔记
    spatial index (空间索引)
    hadoop 的疑问
    numpy 矩阵的运算
  • 原文地址:https://www.cnblogs.com/clockwhite/p/12214500.html
Copyright © 2020-2023  润新知