【学习笔记】卢卡斯定理

用途

  当C(a,b)较大,p较小时,求C(a,b)%p,上界为plogpa

定理

  

  (证明略)

  处理过程就和就p进制数相似,%p,/p,知道a,b中一个为0。

  对于C(mi,ni)%p,求解过程如下:

  C(mi,ni)=mi!/ni!/(m-n)!,设C(mi,ni)%p=x

  mi!/(m-n)i!=x*n!(mod p)

  mk=mi!/(m-n)i!%p(这个是可以算的)  nk=ni!%p(这也可以)

  mk=x*nk(mod p) 

  因为gcd(nk,p)=1,所以nk有逆元,两边同乘逆元  逆元求法

  x=mk*(nk)^(-1)(mod p)   (此处^-1为逆元)

  就求出来了。

代码

  

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<map>
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)<(b)?(a):(b)
#define INF 0x7f7f7f7f
#define MAX_INT 0x7fffffff
#define pi 3.1415926
typedef long long LL;
typedef unsigned int uint;
using namespace std;
LL inv(LL a,LL p){//a^(p-2)
    LL n=p-2,ans=1;
    while(n){
        if(n&1){
            ans=ans*a%p;
        }
        a=a*a%p;
        n>>=1;
    }
    return ans;
}
LL C(LL a,LL b,LL p){
    if(b>a)return 0;
    if(b==a)return 1;
    LL ai=1,bi=1;
    if(b>b-a)b=b-a;
    for(int i=0;i<b;i++){
        ai=ai*(a-i)%p;
        bi=bi*(b-i)%p;
    }
    return ai*inv(bi,p)%p;
}
LL lucas(LL a,LL b,LL p){
    LL ans=1;
    while(a&&b){
        ans=(ans*C(a%p,b%p,p))%p;
        a/=p;
        b/=p;
    }
    return ans;
}
int main(){
    int t;
    cin>>t;
    LL n,m,p;
    while(t--){
        cin>>n>>m>>p;
        cout<<lucas(n,m,p)<<endl;    
    } 
    return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/Gsimt/p/10085240.html