Lucas定理---组合数取模

A、B是非负整数,p是质数。AB写成p进制:A=a[n]a[n-1]…a[0],B=b[n]b[n-1]…b[0]。
则组合数C(A,B)与C(a[n],b[n])C(a[n-1],b[n-1])…*C(a[0],b[0]) modp同余
即:Lucas(n,m,p)=c(n%p,m%p)*Lucas(n/p,m/p,p)
然而如果p很大c(n%p,m%p)也是会溢出的,这里要用到m!(n-m)!的逆元。(虽然我并不知道逆元什么东西    /(ㄒoㄒ)/~~ 感觉自己差的太多)

根据费马小定理(并不懂这个定理怎么证明的 (@﹏@)~):
已知(a, p) = 1,则 ap-1 ≡ 1 (mod p), 所以 a*ap-2 ≡ 1 (mod p)。
也就是 (m!(n-m)!)的逆元为 (m!(n-m)!)p-2

下面是模板

#define ll long long 
ll fac[100003];
void Init(ll p){
    fac[0] = 1;
    for (int i = 1; i <= p; i++){
        fac[i] = (fac[i-1]*i)%p;
    }
}
ll Pow(ll a, ll b, ll p){  //(a^b)%p
    ll ret = 1;
    while(b){
        if (b&1){
            ret = (ret*a)%p;
        }
        a = (a*a)%p;
        b >>= 1;
    }
    return ret;
}
ll Lucas(ll a, ll b, ll p){
    ll ret = 1, aa, bb;
    while(a && b){
        aa = a%p;
        bb = b%p;
        if (aa < bb)    return 0;
        ret = (ret*fac[aa]*Pow(fac[bb]*fac[aa-bb]%p, p-2, p))%p;
        a /= p;
        b /= p;
    }
    return ret;
}

hdu 3037
http://acm.hdu.edu.cn/showproblem.php?pid=3037
计算C(N+M,M)%P

#include <bits/stdc++.h> 
#define ll long long 
using namespace std;  
ll fac[100003];
void Init(ll p){
    fac[0] = 1;
    for (int i = 1; i <= p; i++){
        fac[i] = (fac[i-1]*i)%p;
    }
}
ll Pow(ll a, ll b, ll p){  //(a^b)%p
    ll ret = 1;
    while(b){
        if (b&1){
            ret = (ret*a)%p;
        }
        a = (a*a)%p;
        b >>= 1;
    }
    return ret;
}
ll Lucas(ll a, ll b, ll p){
    ll ret = 1, aa, bb;
    while(a && b){
        aa = a%p;
        bb = b%p;
        if (aa < bb)    return 0;
        ret = (ret*fac[aa]*Pow(fac[bb]*fac[aa-bb]%p, p-2, p))%p;
        a /= p;
        b /= p;
    }
    return ret;
}
int main() {
#ifndef ONLINE_JUDGE 
    freopen("1.txt", "r", stdin);
#endif
    int T;  
    ll n, m, p;  
    scanf("%I64d", &T);
    while (T--) {  
        scanf("%I64d%I64d%I64d", &n, &m, &p);
        Init(p);
        printf("%I64d\n", Lucas(n+m, m, p));
    }  
    return 0;  
} 

HDU 4349 Xiao Ming’s Hope
http://acm.hdu.edu.cn/showproblem.php?pid=4349
Lucas定理推广

#include <bits/stdc++.h>
#define ll long long
#define N 1005 
using namespace std;
int main(){
#ifndef ONLINE_JUDGE 
    freopen("1.txt", "r", stdin);
#endif
    int i, j, k, T, t;
    long long n = 10, ans;
    while(~scanf("%lld", &n)){
        t = 0;
        while(n){
            t += (n&1);
            n >>= 1;
        }
        printf("%lld\n", (long long)pow(2, t));
    }
    return 0;
}

你可能感兴趣的:(Lucas定理---组合数取模)