码迷,mamicode.com
首页 > 其他好文 > 详细

Lucas卢卡斯定理

时间:2018-11-02 23:51:52      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:分析   new   quick   span   inline   \n   阶乘   for   int   

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}(modp)\)

也就是

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

也就是

\(Lucas(n,m)\)%p=C(n%p,m%p)*\(Lucas(n/p,m/p)\)%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(1\le n,m,p\le 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\n",lucas(m+n,m));
    }
    return 0;
}

Lucas卢卡斯定理

标签:分析   new   quick   span   inline   \n   阶乘   for   int   

原文地址:https://www.cnblogs.com/PPXppx/p/9898506.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!