Lucas定理——推导及证明

来源:互联网 发布:祛痘消炎的药膏 知乎 编辑:程序博客网 时间:2024/06/06 04:23

                                     Lucas定理(大组合数取模)


一、定义:

    当n、m为大数,p为素数时,Lucas定理是用来求 c(n,m) mod p的值。适用领域范围在数论中求大组合数取模。

  表达式:C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p

二、定理内容:

Lucas定理:我们令n=sp+q , m=tp+r .(q ,r ≤p)
那么:
(在编程时你只要继续对
  
调用Lucas定理即可。
代码可以递归的去完成这个过程,其中递归终点为t = 0 ;
时间O(logp(n)*p))。

三、证明及推导:  (该过程边看边写效果更佳!)

要证:C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p

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

  证明:

            已知p是素数,n、m、p为整数。

1.由二项式定理得:
                ,且 

2.由费马小定理得:

(1)式 :(1+x)^p ≡ (1+x)(mod p).
(2)式 :(1+x^p)≡ (1+x)(mod p).     (因为x^p与x取模p同余,同时加1也同余

 则由上式可知:
                              (1+x)^p ≡  (1+x^p)(mod p)  (记为(3)式)

3.n = n/p*p + n%p . 则:
               (1+x)^p(mod p) = (1+x)^(n/p*p)*(1+x)^(n%p)mod p

      由式3得:             (1+x)^p(mod p)= (1+x^p)^(n/p)*(1+x)^(n%p)mod p

将上式由二项式公式可转化为:(这一排你用手写看一下吧,这编辑器里太难敲了……)

   ∑(n,z=0)C(n,z)* x^z (mod p)=∑(n/p,i=0)C(n/p,i)* x^(p*i)*∑(n%p,j=0)C(n%p,j)* x^j(mod p)

任意一个Z,必存在一个i,j满足:x^z = x^(p*i)*x^j(即满足:n = n/p*p + n%p),当且仅当:i=z/p,j=z%p 时成立            
此时:          
               C(n,m)=C(n/p,m/p)*C(n%p,m%p)  成立

得证!

代码求解过程中,不断将C(n/p,m/p)拆分化简,实质是一直在计算C(n%p,m%p),即:
C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p
等价于C(n,m)%p=C(n/p/p,m/p/p)*C(n/p%p,m/p%p)%p
等价于C(n,m)%p=C(n/p/p/p,m/p/p/p)*C(n/p/p%p,m/p/p%p)%p
等价于…
直到拆分至m=0,递归完成。


四、逻辑代码:

#include<iostream>using namespace std;typedef long long ll;ll fastmod(ll a,ll b,ll p) //费马小定理{    ll cnt=1;    while(b)    {        if(b&1)            cnt=(cnt*a)%p;        a=(a*a)%p;        b>>=1;    }    return cnt;}ll Comb(ll a,ll b,ll p) //组合数{    ll ca=1,cb=1,tmp=1;;    if(a<b) return 0;    if(a==b) return 1;    if(b>a-b) b=a-b;    for(ll i=0;i<b;i++)    {        ca=(ca*(a-i))%p;        cb=(cb*(b-i))%p;    }    tmp=(ca*fastmod(cb,p-2,p))%p;   //除法转换求逆元    return tmp;}ll Lucas(ll n,ll m,ll p){    ll ans=1;    while(n&&m&&ans)    {        ans=(ans*Comb(n%p,m%p,p))%p;   //拆分+递归        n/=p;        m/=p;    }    return ans;}int main(){    ll n,m,p;    while(cin>>n>>m>>p)    {        ll ans=Lucas(n,m,p);        cout<<ans<<endl;    }    return 0;}
















~step by step

 
原创粉丝点击