组合数求解

扩展欧几里得算法原理
求解逆元的方法(本文采用扩展欧几里得算法进行求解)
求组合数的两种方法
Lucas定理

#include
#include
#include
#include


using namespace std;

// 扩展欧几里得算法求方程ax+by=gcd(a,b)的一个解
// 返回a,b的最大公约数 
int exGcd(int a, int b, int &x, int &y){
    if(b == 0){
        x = 1;
        y = 0;
        return a;
    }
    int g = exGcd(b, a % b, x, y);
    int temp = x;
    x = y;
    y = temp - a / b * y;
    return g;
}
//求解a模m的逆元的最小整数解 
int inverse(int a, int m){
    int x, y;
    int g = exGcd(a, m, x, y);
    return (x % m + m) % m;
}
//n中选m的组合数,对p取余的结果 
int Cal(int n, int m, int p){
    int res = 1;
    for(int i = 1; i <= m; i++){
        res = res * (n - m + i) % p;
        res = res * inverse(i, p) % p;
    }
    return res;
}
//Lucas定理求解组合数 
int Lucas(int n, int m, int p){
    if(m == 0)
        return 1;
    int C = Cal(n % p, m % p, p);
    return C * Lucas(n / p, m / p, p) % p;
} 

int main(){
    int n, m, p;
    while(scanf("%d%d%d", &n, &m, &p) != EOF){
        printf("%d\n", Lucas(n, m, p));
    }
    return 0;
}



你可能感兴趣的:(组合数求解)