组合数计算相关拓展代码

组合数

#include <algorithm>
#include <cstdio>
#include <iostream>
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MOD = 1e9 + 7;
const int maxn = 1e9 + 10;

inline int mul(int a,int b){
	return ((a % MOD) * (b % MOD)) % MOD; 
}

//快速幂计算(a^b) % MOD
inline int qpow(int a,int b) {
    int ans = 1;
    while(b){
        if(b & 1) ans = (ans * a) % MOD;
        a = mul(a,a);
        b >>= 1;
    }
    return ans;
}

//计算b的逆元
inline int inv(int b)   {
    return qpow(b,MOD-2);
}

//计算(a / b) % MOD
inline int divv(int a,int b)  {
    return ((a%MOD)*(inv(b)%MOD))%MOD;
}

//mxx以内素数表
bool prime[maxn];
int cnt;
inline vector<int> nPrime(int mxx){
    cnt = 0;
    vector<int> v;
    memset(prime, true, sizeof(prime));
    prime[0] = prime[1] = false;///表明true为质数
    for (int i = 2; i <= mxx; ++i){
        if (prime[i]){
        	v.push_back(i),cnt++;
		}
        //此处边界判断为rec[j] <= maxn / i,如果写成i * rec[j] <= maxn,需要确保i * rec[j]不会溢出int
        for (int j = 0; j < cnt && v[j] <= mxx / i; ++j){
            prime[i * v[j]] = false;
            if (i % v[j] == 0)
                break;
        }
    }
    return v;
}

//计算n!中素数m的次数
int dPrime(int n, int m) {
	int pow = 0;
	while (n >= m) {
		int temp = n / m;
		pow += temp;
		n = temp;
	}
	return pow;
}

//极小数 时空复杂度 On  O1 
inline int calc1 (int a, int b){
	int res = 1;
	for(int i = 1;i <= b;i++){
		res = mul(res, (a - b + i)) / i;
	}
	return res;
}

//较大数 时空复杂度 On O1 ,逆元求除 
inline int calc2 (int a, int b){
	int res = 1;
	for(int i = 1;i <= b;i++){
		res = mul(res, divv(a - b + i, i));
	}
	return res;
}

//极大数 时空复杂度 On ~ Ologn On ,分解质因数,阶段取乘,10000000以下上面的快, 20000000以上时这个快,中间看电脑 
inline int calc3(int n, int m) {
	int ans = 1;
	vector<int> v = nPrime(n);
	for (int i = 0; i < v.size(); i++) {
		int k = v.at(i),pow;
		pow = dPrime(n, k) - dPrime(m, k) - dPrime(n - m, k);
		ans = mul(ans,qpow(k,pow));
	}
	return ans;
}

clock_t st,ed;
double endtime;
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	printf("%lld\n",calc1(9,4));
	//较大数下时间比较
	
	st = clock(); 
	printf("%lld\n",calc2(90000000,40000000));
	ed = clock();
	endtime=(double)(ed-st)/CLOCKS_PER_SEC;
	cout << "Total time:" << endtime * 1000 << "ms" << endl;	//ms为单位
	
	st = clock();
	printf("%lld\n",calc3(90000000,40000000));
	ed = clock();
	endtime=(double)(ed-st)/CLOCKS_PER_SEC;
	cout << "Total time:" << endtime*1000 << "ms" << endl;
	
	st = clock(); 
	printf("%lld\n",calc2(90000000,40000000));
	ed = clock();
	endtime=(double)(ed-st)/CLOCKS_PER_SEC;
	cout <<"Total time:" << endtime*1000 << "ms" << endl;
	
	st = clock();
	printf("%lld\n",calc3(90000000,40000000));
	ed = clock();
	endtime=(double)(ed-st)/CLOCKS_PER_SEC;
	cout << "Total time:" << endtime*1000 << "ms" << endl;
	return 0;
}
posted @ 2021-06-15 19:47  0xYuk1  阅读(56)  评论(0)    收藏  举报