首页 > 其他分享 >组合数

组合数

时间:2024-02-16 19:44:41浏览次数:22  
标签:infact 组合 int text MAX fact mod

一、预处理组合数

核心

\[C_a^b = C_{a-1}^b + C_{a-1}^{b-1} \]

适用范围:\(a\) 较小的情况下,如 \(a \leq 10^3\)。
算法简析:令 \(\text{C[n][k]}=C_n^k\),规定 \(\text{C[0][0] = 1}\),则

\[\begin{split} \text{C[n][k]}=\begin{cases} 1&,k==0\\ \text{C[n - 1][k] + C[n - 1][k - 1]}&,0<k\leq n~and~n\geq1 \end{cases} \end{split} \]

#define MAX 4000
#define MOD 6662333

int C[MAX][MAX], n;

void solve(void)
{
	for (int i = 0; i <= n; i++)
		for (int j = 0; j <= i; j++)
			if (j == 0)    C[i][j] = 1;
			else
				C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD; 
}

预处理后,直接访问 \(\text{C[n][k]}\),就能得到 \(C_n^k\) 的值。


二、预处理阶乘

核心

\[C_a^b=\frac{a!}{b!(a-b)!}=a!\ast (b!)^{-1}\ast ((a-b)!)^{-1} \]

适用范围:\(a\) 较大的情况下,如 \(a\leq 10^{5}\)。
算法简析
先来看逆元费马小定理的定义:

  • 1、逆元:对于模 \(m\),有两个数 \(a\) 和 \(b\),若 \(ab\equiv1(\text{mod}~m)\),即 \(a\) 和 \(b\) 的乘积除以 \(m\) 的余数为1,则 \(a\) 和 \(b\) 互为模 \(m\) 意义下的乘法逆元。记 \(b=a^{-1},~a=b^{-1}\)。
  • 2、费马小定理:若 \(p\) 是一个素数,且 \(a\) 不被 \(p\) 整除,则 \(a^{p-1}\equiv1(\text{mod}~p)\),即 \(a^{p-1}\) 除以 \(p\) 的余数为1。
    由模运算的性质,\(\equiv\) 两边同乘 \(a\) 的逆元 \(a^{-1}\),得 \(a^{p-2}\equiv a^{-1}(\text{mod}~p)\)。在模 \(p\) 的意义下,\(a^{p-2}\) 和 \(a^{-1}\) 等价。求 \(a^{-1}\),就转换为求 \(a^{p-2}\)。

现在,我们的重点是求阶乘阶乘的逆元。我们用两个数组 fact[]infact[] 分别表示阶乘(fact[a] 为 \(a!\))和阶乘的逆元(infact[a] 表示 \((a!)^{-1}\))。规定 \(\text{fact[0] = infact[0] = 1}\)。

  • 1、阶乘:由

\[a!=(a-1)!\ast a \]

得,

\[\text{fact[a] = fact[a - 1] * a} \]

  • 2、阶乘的逆元:由费马小定理,在模 \(p\) 下,

\[\begin{split} (a)^{p-2}&\equiv (a)^{-1}(\text{mod}~p) \\ (a!)^{-1}&=((a-1)!)^{-1}\ast a^{-1} \end{split} \]

得,

\[\begin{split} \text{infact[a]}&=\text{infact[a - 1]} \ast a^{-1} \\ a^{-1}&=\text{pow(a, p - 2) mod p} \end{split} \]

注:计算逆元时,可以通过快速幂来提高算法效率。

#define MAX 4000
#define MOD 6662333

int fact[MAX], infact[MAX], n;

typedef long long ll;

int qum(int x, int n, int mod)
{
	ll ret = 1;
	while (n > 0)
	{
		if (n & 1)    ret = ret * x % MOD;
		x = (ll)x * x % MOD;
		n >>= 1;
	}
	return ret;	
} 

void solve(void)
{
	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] * qum(i, MOD - 2, MOD) % MOD;
	}
}

预处理后,\(C_n^k=\text{fact[n] * infact[k] * infact[n - k]}\)。注意:计算过程中可能会溢出,要进行模运算。


三、卢卡斯定理

核心:卢卡斯定理

\[C_a^b\equiv C_{a~\text{mod}~p}^{b~\text{mod}~p}~·~C_{\lfloor a/p \rfloor}^{\lfloor b/p \rfloor}(\text{mod}~p) \]

适用范围:\(a\) 很大的情况,比如 \(a \leq 10^{18}\)。
算法简析:若 \(a\) 和 \(b\) 很大,我们可以通过卢卡斯定理缩小 \(a\) 和 \(b\),直至 \(a,~b< p\) (\(p\) 一般是较小的素数)。这时,在使用前两种方法求解。

#define MAX 4000
#define MOD 6662333

int fact[MAX], n;

typedef long long ll;

int qum(int x, int n, int mod)
{
	ll ret = 1;
	while (n > 0)
	{
		if (n & 1)    ret = ret * x % MOD;
		x = (ll)x * x % MOD;
		n >>= 1;
	}
	return ret;	
} 

void init(void)
{
	fact[0] = 1;
	for (int i = 1; i <= n; i++)
	{
		fact[i] = (ll)fact[i - 1] * i % MOD;
	}
}

int C(int a, int b, int mod)
{
	if (a < b)    return 0;
	return (ll)fact[a] * qum(fact[b], mod - 2, mod) % mod * qum(fact[a - b], mod - 2, mod) % mod;
}

int lucas(int a, int b, int mod)
{
	if (a < mod && b < mod)    return C(a, b, mod);
	return (ll)C(a % mod, b % mod, mod) * lucas(a / mod, b / mod, mod) % mod;
}

标签:infact,组合,int,text,MAX,fact,mod
From: https://www.cnblogs.com/hoyd/p/18017404

相关文章

  • vue 组合api 中父传子 provide和inject
    父组件import{provide,ref}from'vue'provide('data-key','thisisroomdata')子组件import{inject}from"vue";constroomData=inject('data-key')......
  • 组合基础
    OI中的组合,基本指组合计数。组合极值一般是贪心题或者dp题。【组合数】组合数\(C^m_n=(^n_m)\)。注意:求逆元前,请一定判断清楚,是否可能不存在逆元!!!\(C^m_n=C^m_{n-1}+C^{m-1}_{n-1}\)。c[n][m]=c[n-1][m]+c[n-1][m-1];这个方法主要问题在于空间。优点:可以......
  • leetcode 17 电话号码的字母组合
     解题关键点:用递归方法classSolution{public:vector<string>mapping={"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};voidcom......
  • 排列与组合
    Thenumberofwaystochoose\(x\)itemsfrom\(n\)itemsisgivenbythebinomialcoefficient,whichiscalculatedusingthecombinationformula:\[C(n,x)=\frac{n!}{x!(n-x)!}\]Thisisreadas"nchoosex"andrepresentsthenum......
  • 24/02/12 [六省联考 2017] 组合数问题
    题目描述组合数\(C_n^m\)表示的是从\(n\)个互不相同的物品中选出\(m\)个物品的方案数。举个例子,从\((1,2,3)\)三个物品中选择两个物品可以有\((1,2)\),\((1,3)\),\((2,3)\)这三种选择方法。根据组合数的定义,我们可以给出计算组合数\(C_n^m\)的一般公式:\[C_n^m......
  • 力扣回溯 深度优先搜索 dfs 之 17. 电话号码的字母组合
    给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按任意顺序返回。给出数字到字母的映射如下(与电话按键相同)。注意1不对应任何字母。 示例1:输入:digits="23"输出:["ad","ae","af","bd","be","bf","cd","ce","cf&qu......
  • 代码随想录 day44 零钱兑换 II 组合总和 Ⅳ
    零钱兑换II这里组合类问题用上了dp[j]=dp[j-nums[i]]这个递推式由于说了硬币可以用无数次也就是这是个完全背包问题这里先遍历物品再遍历背包就是算了组合数反过来就是算排列数组合总和Ⅳ这题就是组合类问题的排列数模板题......
  • 探索C语言中的联合体与枚举:数据多面手的完美组合!
    ​✨✨欢迎大家来到贝蒂大讲堂✨✨......
  • Python实现软件设计模式9:组合模式 Composite Pattern
    动机如何将容器和叶子进行递归组合,使得用户在使用时无须对它们进行区分,可以一致地对待容器和叶子?典型案例如:文件系统,在树形目录结构中,包含文件和文件夹两类不同的元素;在文件夹中可以继续包含文件或子文件夹,在文件中不能再包含子文件或者子文件夹。概念组合多个对象形成树形......
  • 生成随机字符串(数字、字母、特殊符号组合)
    多用于随机复杂密码。如果“数字、字母、特殊符号”都放在一个数组中,随机生成的不一定会同时具备三者的组合,所以,只能分开,再自定义规则组合在一起(虽然不是很完美)以下便是实例,调用的时候加上“密码长度(不少于6位)”的判断提示!///<summary>///生成随机密码///</summary>/......