组合计数4中模板

组合计数(1)

#include <iostream>

using namespace std;

// http://t.csdn.cn/VpZeL

// 适合处理c(a,b)数据量大、但a 和 b 数值较小的,用组合数数组预处理

const int N = 2010, mod = 1e9 + 7;

int c[N][N]; // c[i][j]表示 C i取j

// 预处理组合数数组
void init_C()
{
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j <= i; j++)
		{
			if (j == 0 || i == j)
			{
				c[i][j] = 1;
			}
			else
			{
				// 答案很大时模掉一个指定数
				c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
			}
		}
	}
}

int main()
{
	init_C();


	return 0;
}

组合计数(2)

#include <iostream>

using namespace std;

typedef long long LL;

const int N = 100010, mod = 10e9 + 7;

// 使用公式 c(a,b) = a! / ((a-b)! * b!)
// 适合a和b数值比较大的

int fact[N], infact[N];// fact[i] 表示i的阶乘 % mod
                       // infact[i] 表示i的阶乘的逆 % mod

// 快速幂
int qmi(int a, int k, int p)
{
	int res = 1;

	while (k)
	{
		if (k & 1)
		{
			res = (LL)res * a % p;
		}
		a = (LL)a * a % p;
		k = k >> 1;
	}

	return res;
}

int main()
{
	fact[0] = infact[0] = 1;

	for (int i = 1; i < N; i++)
	{
		fact[i] = (LL)fact[i - 1] * i % mod;

		// 快速幂求逆元
		infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
	}

	int a, b;
	cin >> a >> b;
	
	// 按照公式计算结果
	cout << (LL)fact[a] * infact[b] % mod * infact[a - b] % mod;

	return 0;
}

组合计数(3)

#include <iostream>

using namespace std;

// a和b的数值特别大,求出 C(a, b) % mod 的结果

// 卢卡斯定理:C(a,b) 同余于 C(a % mod, b % mod) * C(a / mod, b / mod)


typedef long long LL;

const int mod = 10e5 + 5;
// a b 的范围为0 ~ 10^18


// 快速幂
int qmi(int a, int k, int p)
{
	int res = 1;

	while (k)
	{
		if (k & 1)
		{
			res = (LL)res * a % p;
		}
		a = (LL)a * a % p;
		k = k >> 1;
	}

	return res;
}


// 使用组合计数(2)的方法计算
int C(int a, int b)
{
	int res = 1;
	
	for (int i = 1, j = a; i <= b; i++, j--)
	{
		res = (LL)res * j % mod;
		res = (LL)res * qmi(i, mod - 2, mod) % mod;
	}

	return res;
}

// 卢卡斯定理实现
int lucas(LL a, LL b)
{
	if (a < mod && b < mod)
	{
		return C(a, b);
	}

	return (LL)C(a % mod, b % mod) * lucas(a / mod, b / mod) % mod;
}

int main()
{
	// a和b的数值大,用longlong接收
	LL a, b;
	cin >> a >> b;

	return 0;
}

组合计数(4)

#include <iostream>
#include <vector>
using namespace std;

// 利用高精度输出整个 C(a,b)

// 步骤:  (1)将整个 C(a,b) 分解质因数,C(a,b) = a! / ((a - b)! * b!) ,所以 p在 C(a,b) 中的次数 = p在 a! 阶乘中的次数 - p在 (a - b)! 中的次数 - p在 b 阶乘中的次数
//         (2)再用高精度将所有质因数乘进去

const int N = 5010;

int primes[N], cnt; // 筛选出质数放入
bool st[N];

int num[N]; // 记录每一个质数在分解质因数中的次数


// 筛选除质数,便于后面分解质因数
void get_primes(int n)
{
	for (int i = 2; i <= n; i++)
	{
		if (!st[i])
		{
			primes[cnt++] = i;
		}


		for (int j = 0; primes[j] <= n / i; j++)
		{
			st[primes[j] * i] = true;

			if (i % primes[j] == 0)
			{
				break;
			}
		}
	}
}

// 求出 n!中 p 的次数
// 公式:get(n,p) = (n / p) + (n / p^2) + (n / p^3) + ……
int get(int n, int p)
{
	int res = 0;

	while (n)
	{
		res += n / p;
		n /= p;
	}

	return res;
}


// 高精度乘法:C = A * b, A >= 0, b > 0
vector<int> mul(vector<int>& A, int b)
{
	vector<int> C;

	for (int i = 0, t = 0; i < A.size() || t; i++)
	{
		if (i < A.size())
		{
			t += A[i] * b; // 不同于一般乘法
		}
		C.push_back(t % 10);
		t /= 10;
	}

	return C;
}

int main()
{
	int a, b;
	cin >> a >> b;

	// 预处理出 1 - a中的质数,方便后面分解质因数
	get_primes(a);

	// 求出每个质数在 C(a,b) 中的次数
	for (int i = 0; i < cnt; i++)
	{
		int p = primes[i];

		num[i] = get(a, p) - get(b, p) - get(a - b, p);
	}

	// 将每个质因数乘入高精度中
	vector<int> res;
	res.push_back(1);

	for (int i = 0; i < cnt; i++)
	{
		for (int j = 0; j < num[i]; j++)
		{
			res = mul(res, primes[i]);
		}
	}

	// 输出结果,注意是从后往前输出
	for (int i = res.size() - 1; i >= 0; i--)
	{
		cout << res[i];
	}

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值