组合数_卢卡斯定理_费马小定理_高精度组合数

注:当遇到 ( a / b ) m o d   p (a/b)mod\ p (a/b)mod p的形式时,采用 a ∗ p − 1 m o d   p a*p^{-1}mod\ p ap1mod p进行计算。计算 p − 1 p^{-1} p1时,由于p是质数,采用费马小定理计算 p − 1 p^{-1} p1
组合数问题1:
当求的数较小,但是求得次数较多时,采用打表的方式进行记录查询。
在这里插入图片描述

#include<iostream>

using namespace std;

const int N = 1e5+5,mod = 1e9+7;;
typedef long long LL;

LL fac[N],infac[N];

LL qmi(LL a,LL p,LL q){
    
    
	//快速幂求逆元
    LL res =1;
    while(p){
    
    
        if(p&1) res=res*a%q;
        a=a*a%q;
        p>>=1;
    }
    return res;
}

int main(){
    
    
    fac[0]=infac[0]=1;
    for(int i=1;i<N;i++){
    
    
        fac[i]=fac[i-1]*i%mod;
        infac[i]=(LL)infac[i-1]*qmi(i,mod-2,mod)%mod;
    }
    int n;
    cin>>n;
    while(n--){
    
    
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%d\n",fac[a]*infac[b]%mod*infac[a-b]%mod);
    }
    return 0;
}

组合数问题2:
当数较大,但是查询次数较少时,采用卢卡斯定理进行计算。
卢卡斯定理:
C a b 三 C a   m o d   p b   m o d   p ∗ C a / p b / p ( m o d   p ) C^b_a三C^{b\ mod \ p}_{a\ mod \ p}*C^{b / p}_{a/ p}(mod\ p) CabCa mod pb mod pCa/pb/p(mod p)
在这里插入图片描述

#include<iostream>

using namespace std;
typedef long long LL;
int p;

LL qmi(LL a, LL k) {
    
    
	//快速幂求逆元
    LL res = 1;
    while (k) {
    
    
        if (k & 1) res = res * a % p;
        k >>= 1;
        a = a * a % p;
    }
    return res;
}

LL C(LL a, LL b) {
    
    
	//计算组合数
    LL res = 1;
    for (int i = b; i >= 1; i--) {
    
    
        res = res * a % p;
        res = res * qmi(i, p - 2) % p;
        a--;
    }
    return res;
}

LL locas(LL a, LL b) {
    
    
	//当b<p的时候,说明locas(a / p, b / p) % p=1
    if (b < p) return C(a % p, b % p);
    return C(a % p, b % p)* locas(a / p, b / p) % p;
}

int main() {
    
    
    int n;
    cin >> n;
    while (n--) {
    
    
        LL a, b;
        cin >> a >> b >> p;
        cout<<locas(a, b)<<endl;
    }
    return 0;
}

组合数问题3:
高精度组合数。思路:通过对分子分母进行分解质因数,然后上下的质因数消去一部分,就可以得到最终的解。
a阶乘分解质因数中p的指数是 a p + a p 2 + . . . \frac a p +\frac a p^2 +... pa+pa2+...其中 / / /是整除的意思
在这里插入图片描述

#include<iostream>
#include<vector>

using namespace std;

const int N = 5e5 + 5;

int prime[N], cnt;
bool st[N];
int sum[N];

void get_prime(int n) {
    
    
	\\线性筛筛素数
    for (int i = 2; i <= n; i++) {
    
    
        if (!st[i]) prime[cnt++] = i;
        for (int j = 0; prime[j] <= n / i; j++) {
    
    
            st[prime[j] * i] = true;
            if (i % prime[j] == 0) break;
        }
    }
}

int get(int a, int p) {
    
    
    //得到a!中p质因子的个数
    int res = 0;
    while (a) {
    
    
        res += a / p;
        a /= p;
    }
    return res;
}

vector<int > mul(vector<int > a, int b) {
    
    
		//高精度乘法
    vector<int> k;
    int t = 0;
    for (int i = 0; i < a.size(); i++) {
    
    
        t += a[i] * b;
        k.push_back(t % 10);
        t /= 10;
    }
    while (t != 0) {
    
    
        k.push_back(t % 10);
        t /= 10;
    }
    return k;
}

int main() {
    
    
    int a, b;
    cin >> a >> b;
    get_prime(a);//线性筛求素数的个数
    for (int i = 0; i < cnt; i++) {
    
    
        sum[i] = get(a, prime[i]) - get(b, prime[i]) - get(a - b, prime[i]);
    }
    vector<int> ans;//0是低位
    ans.push_back(1);
    for (int i = 0; i < cnt; i++) {
    
    
        for (int j = 0; j < sum[i]; j++) {
    
    
            ans = mul(ans, prime[i]);
        }
    }
    for (auto it = ans.rbegin(); it != ans.rend(); it++) {
    
    
        cout << *it;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45931661/article/details/119960696