首页 > 其他 > 详细

[学习笔记]Lucas定理

时间:2020-01-19 17:39:00      阅读:65      评论:0      收藏:0      [点我收藏+]

Lucas卢卡斯定理

一.什么是lucas定理

? lucas定理是用来解决组合数取模问题的,即求解
\[ C_n^m\pmod{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的值也为零,但是这样是正确的吗?显然是的。

? 为了证明他的正确性,我们首先保证一开始我们要求解的问题有解,即\(n\geq m\),记
\[ \begin{align} &n=k_n*p+r_n\&m=k_m*p+r_m\\because& r_n<r_m,n\geq m \\therefore& n-m>p\\because&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;
}

[学习笔记]Lucas定理

原文:https://www.cnblogs.com/clockwhite/p/12214500.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!