快速求解组合数

快速入门之——乘法逆元求组合数 逆元+快速幂+阶乘求组合数(快速入门) 文章目录逆元+快速幂+阶乘求组合数(快速入门)前言:何为逆元?怎么求逆元?怎么求阶乘逆元?相关代码实现: 前言: 大家基本上应该都知道用杨辉三角法求组合数C(n,m)(n为下标) 也就是直接暴力打表求法O(n*m): for(int i=0;i<=n;i++){ c[i][0]=c[i][i]=1; for(int j=1;j<i;j++) ... 阅读详情

欢迎访问我的个人博客:http://www.ghost-him.com/ 文章优先发布到个人博客上。

组合是数学的重要概念之一。从 n n n 个不同元素中每次取出 m m m 个不同元素 ( 0 ⩽ m ⩽ n ) (0 \leqslant m \leqslant n) (0⩽m⩽n) ,不管其顺序合成一组,称为从 n n n 个元素中不重复地选取 m m m 个元素的一个组合。所有这样的组合的种数称为组合数。

本文将通过动态规划的思维和数学方法来求解组合数。

方法一:动态规划

适用数据范围:c[i][j],i < 2000 且 j < 2000

通过公式
C n m = C n − 1 m − 1 + C n − 1 m C_{n}^{m} = C_{n-1}^{m-1} + C_{n-1}^{m} Cnm​=Cn−1m−1​+Cn−1m​
可知,求一个组合数时,只需要知道之前的两个组合数,再通过相加即可得出。

我们要理解这个公式,可以既可以通过数学公式推导,可以通过算法中动态规划的思维来理解。在高中的时候,老师已经讲过这个公式的数学推导了,所以这里就不赘述了。

这里讲一下动态规划的思维。

这个动态规划的思维是01 背包模型。我们设变量 C[i][j] 表示的是第下标是 i,上标是 j 的组合数,即 C i j C_{i}^{j} Cij​
。即,这个变量表示的是在 i 个物品中选 j 个物品的方案数。我们在选第 j 个物品时,有两种方案:

  1. 第一种是选第 j 个物品。
  2. 第二种是不选第 j 个物品。

我们先看第一种情况:如果选了第 j 个物品,那么当前的状态就是在 i 个物品中选了 j 个物品。同时,由于这个状态是从上一个状态转移过来的。只有当上一个状态是选了 j - 1 个物品时,加上当前的物品,才可以是当前的这个状态。因此,上一个状态就是在 i - 1 个物品中选了 j - 1 个物品的方案,即 c[i - 1][j - 1]。

我们再来看第二种情况:如果我们不选这个物品。那就说明当前的状态选的物品的个数和上一个状态选的物品的个数一致。因此,上一个状态就是在 i - 1 个物品中选 j 个物品的方案,即 c[i - 1][j]。

由于求的是方案的个数(组合数的定义),所以当前的状态等于转移的状态之和。即 c[i][j] = c[i - 1][j - 1] + c[i - 1][j] 。

题目链接:AcWing 885. 求组合数 I

我们来看一下代码的写法

#include <iostream>
#include <cstring>

using namespace std;

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

// 询问的个数
int n;
// c[i][j] 表示的值
int c[N][N];

int main () {
    // 根据题目中询问的数据的范围,预处理一下c[i][j]的值
	for (int i = 0; i <= 2000; i ++) {
		for (int j = 0; j <= i; j ++) {
		    // c[i][0] = 1
			if (j == 0) c[i][j] = 1;
			else {
			    // 根据公式写
				c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
			}
		}
	}
	// 读取询问的次数
	cin >> n;
	for (int i = 0; i < n; i ++) {
		// 读取每次查询的 下标a 和 上标j
		int a, b;
		scanf("%d%d", &a, &b);
		// 输出c[a][b]的值
		printf("%d\n", c[a][b]);
	}
	
	return 0;
}

方法二:数学公式

适用数据范围:c[i][j],i < 10000 且 j < 10000

通过公式
C n m = P n m P n = n ! m ! ( n − m ) ! C_{n}^{m} = \frac{P_{n}^{m}}{P_{n}}=\frac{n!}{m!(n-m)!} Cnm​=Pn​Pnm​​=m!(n−m)!n!​
可知如果想要求一个组合数,只需要通过阶乘运算就可以得出。

当我们要算的数字很小的时候,我们可以通过直接除法的方式来直接求出一个组合数。但是,在取余的环境下,我们不可以直接用除法。此时,如果我们需要乘以一个数,我们可以乘以这个数的逆元。

假设 A A A 的逆元是 a a a,那么
C A m o d    p ≡ C ∗ a m o d    p \frac{C}{A} \mod p \equiv C*a \mod p AC​modp≡C∗amodp
通过逆元,我们可以将除法变成乘法。

设一个 fact[i] 表示 i ! i! i! ;infact[i] 表示 i ! i! i! 的逆元;c[i][j] 表示 C i j C_{i}^{j} Cij​。那么 c[i][j] = fact[i] * infact[j] * fact[n - m]。

在这里,如何计算一个逆元的值呢?

通过费马小定理,我们可以知道,如果 p 是一个质数,而整数 a 不是 p 的倍数,那么
a p − 1 ≡ 1 m o d    p a^{p-1} \equiv 1\mod p ap−1≡1modp

因此,
C A m o d    p ≡ C ∗ a m o d    p \frac{C}{A} \mod p \equiv C*a \mod p AC​modp≡C∗amodp
1 ≡ a ∗ A m o d    p 1 \equiv a * A \mod p 1≡a∗Amodp
A p − 1 ≡ a ∗ A m o d    p A^{p - 1} \equiv a*A \mod p Ap−1≡a∗Amodp
A p − 2 ≡ a m o d    p A^{p-2} \equiv a \mod p Ap−2≡amodp
所以,当 p 和 A 互质的时候,A 的逆元就是 A p − 2 A^{p-2} Ap−2。

我们来看代码的写法。

题目:AcWing 886. 求组合数 II

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

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

// 要用long long 类型,所以为了少写字母,将long long 定义成LL
typedef long long LL;
// i! 的值和 i! 的逆元
int fact[N], infact[N];

// 快速幂模板,计算A的逆元
LL qmi(LL a, LL b, LL q) {
	LL res = 1;
	while (b) {
		if (b & 1) {
			res = res * a % q;
		}
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}

int main () {
    // 初始化, 0! = 1, 0!的逆元也是1
	fact[0] = infact[0] = 1;
	// 求i!的值和其逆元。
	for (int i = 1; i < N; i ++) {
	    // 根据 (i - 1)! 计算 i! 的值
		fact[i] = (LL) fact[i - 1] * i % mod;
		// 根据 (i - 1)! 逆元的值计算 i! 逆元的值
		infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
	}
	
	int n;
	scanf("%d", &n);
	while (n --) {
		int a, b;
		scanf("%d%d", &a, &b);
		// 输出公式
		printf("%d\n", (LL)fact[a] * infact[b] % mod * infact[a - b] % mod);
	}
	return 0;
}
泛微Ecology流程数据表结构解析:workflow_requestbase和workflow_currentoperator到底怎么关联查询? 本文深入解析泛微Ecology系统中workflow_requestbase和workflow_currentoperator表的结构与关联机制,提供SQL查询语句示例,帮助开发者高效查询流程数据。涵盖待办事项、已办事项、办结事项和流程监控等典型场景,并分享性能优化技巧和常见问题排查指南。 阅读详情

相关推荐

arduino esp8266_Arduino传感器教程 第22章ESP8266 控制 5V 继电器

ESP8266控制5V继电器目录一、NodeMCU二、工作原理本文将使用亚马逊 AlexaEcho 和 ESP8266 控制 5V 继电器。NodeMCUNodeMCU 是一个开源的 IoT 物联网硬件开发板,由于它支持 WIFI 功能且使用方法十分类似 Arduino 开发板,所以近些年获得了越来越多来自全世界的创客朋友们的青睐。NodeMCU 尺寸与 Arduino Nano 类似。...

weixin_39611722的博客 3457

组合数动态规划

个数来,然后剩下的都作为质数,每一种方案当中质数是固定的,对指数使用排列组合,也就是。个数,问集合使用唯一分解定理能表示出多少个数?实际上是你列的式子中的一部分,比如说,你的一种方案是。不超时体会:把所有的判别函数都存进数组。我们知道组合数当中有一个经典的方程为。:嘤,我终于把我上次比赛的题补完了。那么这个题,我们也可以这么来设。个数(前提是质数)应该是底数,则第。首先需要把这些方案分成正交的。转移过来的时候就代表不选择第。状态转移过来的时候就代表第。个符合条件的数的方案。个数对于指数的贡献就是。

weixin_52205764的博客 973

知识图谱的数据挖掘与分析

1. 背景介绍 1.1 数据挖掘的崛起 随着互联网的普及和大数据技术的发展,数据挖掘已经成为了计算机科学领域的热门研究方向。数据挖掘是从大量的、不完全的、有噪声的、模糊的、随机的实际应用数据中,通过计算机科学、统计学、信息论等多学科交叉的方法,挖掘出有用信息和知识的过程。数据挖掘的目标是从数据中发现有

AI天才研究院 1600

求组合数的几种方法

定义 从 n 个不同元素中取出 m 个元素的所有组合的数目 公式 性质 (1) C ( n , m ) = C ( n , n - m ) = C ( n - 1 , m - 1 ) + C ( n - 1 , m ) (2) 实现方法1(杨辉三角) 杨辉三角第 i 行第 j 列对应 C ( i ,j ) 的结果 用动态规划求从 n 个元素中取出 m 个元素的所有组合个数 c [ i ] [ j ] :在 i 个元素中选 j 个 对于当前状态 i j ,可以由两种情况转移而来: 1、前 i - 1 个元

Cosmic_Tree的博客 865

几何修复_ANSYS流体分析:几何前处理

建模及几何处理工具非常多,选择起来让人眼花缭乱。对于仿真而言,高效的对几何进行清理及生成符合仿真要求的几何至关重要。ANSYS SpaceClaim Direct Modeler是基于直接建模思想的新一代3D高效率建模和几何编辑修补软件。SCDM提供了当今最快速、最富有创意的直接建模解决方案。由于它的直接建模能力即使对于导入的其它3D模型(如catia、proe、solid works创建的几何)...

weixin_35778830的博客 2418

SAP_MM模块采购价格确定控制简介

SAP MM模块采购价格确定控制是采购管理中的关键功能,系统通过"价格确定日期"判断条件记录有效性并带出正确价格。文章分析了四种常见业务场景及其对应的价格确定方案:普通采购订单(创建日期)、长期合同(交货日期)、特殊业务(手动输入)和接口下单(系统传入)。详细介绍了配置方法和前台操作步骤,并提供了不同业务类型对应的推荐控制方式汇总表。通过合理设置价格确定日期控制,企业可以确保采购价格准确性,满足各种复杂业务场景下价格管理的需求,从而提高采购管理效率和成本控制能力。

我小时候很黑的博客 738

动态规划-数字组合问题

状态转移方程为dp[i][j]=dp[i-1][j],每一种状态由上一层状态转移,这是新来的那个数没有加上的情况,如果加上的话,就需要比较b这个数和j这个数大小,比如新输入的数为b,如果b>=j的话,转移方程就变成了dp[i][j]=dp[i-1][j]+dp[i-1][j-b]。题目分析与解法:这道题是一个简单的动态规划问题,我们定义dp[i][j]数组用来表示前i个数字能组合成j这个数的组合数,起初dp[0][0]=1,因为前0个数字组合成0的方案数就只有1组,就是什么都不选。

qq_63198287的博客 1243

JAVA:Spring Boot 集成 LibreOffice 实现文档在线转换服务

本文介绍了在企业级应用开发中使用LibreOffice实现文档格式转换的技术方案。通过对比分析商业库、纯Java方案和云服务API的优缺点,重点阐述了LibreOffice在格式兼容性、转换质量和零成本方面的优势。文章详细说明了环境准备步骤,包括Windows/Linux系统安装LibreOffice、解决中文乱码问题以及Docker部署方案。最后提供了Spring Boot项目的基本配置,包括Maven依赖和application.yml配置文件,为构建稳定高效的文档转换服务奠定基础。

木头 520

动态规划求解所有字符的组合数

一,问题描述 给定若干个字符,求解 这些字符能够表示的最多组合个数。比如{'a','b','c'} 一共有七种组合。(每种组合没有重复的字符 且 组合的种数与顺序无关,如 ab 和 ba 是同一种组合) a、b 、c 、ab 、ac 、bc 、abc 其实,求组合个数,可以用公式来求解:具给定 n种字符,一共有  c(n,1)+c(n,2)+...+c(n,n)种不同的组合。其中,c(n,i...

weixin_34081595的博客 383

用 SAP-ABAP-1 把 ABAP 代码读懂:从 Generative AI Hub Orchestration 到 Joule 落地的实战指南

SAP-ABAP-1 是 SAP 推出的 ABAP 专用基础模型,专注于代码解释与理解。它能显著降低企业遗留系统的维护成本,帮助开发人员快速掌握复杂业务逻辑。该模型通过 SAP Generative AI hub 托管,支持 128,000 tokens 的上下文长度,适合分析大型 ABAP 类和 CDS 视图。典型应用场景包括代码解释、迁移辅助和云合规检查。调用需通过 Orchestration service 进行,确保企业级安全治理。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1213

computer planetary——全球生物多样性信息机构 (GBIF)

正如npartitions所表明的,这个Parquet数据集是由许多单独的parquet文件组成的。(GBIF) 是一个由世界各国政府资助的国际网络和数据基础设施,提供记录物种发生的全球数据。重新处理数据的原因有多种,包括主干分类的更改,因此该日期不一定是发生记录最后更改的日期。GBIF 发生数据集结合了来自广泛来源的数据,包括来自自然历史博物馆的标本相关数据、来自公民科学网络的观察和自动环境调查。为了了解最常观察到的物种,我们将对数据集进行分组,并获得每个物种的计数。大多数字段名称对应于。

此星光明博客 1636

[算法][动态规划]计算组合数和排列数

计算组合数和排列数的一些技巧

身披白袍的博客 3150

beegfs读取文件完整流程分析

读取小于512KB文件数据,小于1s 读取15MB文件数据,花费7秒。

wfzy的博客 836

如何快速求解组合数 C(n,m) 取模 【最简单的方法】

如何快速求解组合数 C(n,m) 取模 组合数取模,肯定要用到乘法逆元,像我这种蒟蒻,还不会。 但是我学到了一个更优秀的方法,不仅快速求解C(n,m),而且还可以mod。 这需要用到质因数拆分: 我们知道Cmn=n!(n−m)!m!Cnm=n!(n−m)!m!C_n^m=\frac{n!}{(n-m)!m!}。 那么我们将n!转化成质因数相乘的形式 Px11∗Px22∗...∗Pxk...

XSamsara的博客 AFO 5026

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

组合数快速求解

 对于组合数中要求C(N,M)的话,一般常用的方法就是对除号的上下分别进行质因子分解,但同样是质因子分解也可以有不同的解法.  下面给出一种较快的方法:  将(n!)质因数分解的算法  (注意是直接分解(n!),而不是将(1,2,3...n)一项一项分解)  如果k是一个质数,f(k)表示里质因数K的个数  f(k)=n/k+n/(k*k)+n/(k+k+k)+...n/(k^

jianbisb的专栏 552

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

[二项式系数求解] 快速计算组合数与模运算优化 | NOIP 2011 提高组题解

对于 100% 的数据,有 0 ≤ k ≤ 1000,0 ≤ n,m ≤ k,n + m = k,0 ≤ a,b ≤。输入共一行,包含 5 个整数,分别为 a,b,k,n,m,每两个整数之间用一个空格隔开。这个系数可能很大,输出对 10007 取模后的结果。对于 50% 的数据,有 a = 1,b = 1。NOIP 2011 提高组 day2 第 1 题。对于 30% 的数据,有 0 ≤ k ≤ 10。输出共一行,包含一个整数,表示所求的系数。,请求出多项式展开后。一道二项式定理模板题。

大家好,我是宗嗣令 767

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

组合数的四种求解方式,递推,快速幂,Lucas,高精度&线性筛

组合数学基础

EQUINOX1的博客 2032

快速求解组合数(筛法+快速幂)

a quick way to calculate combinatorial number1.Why we need this method? Anyone who know how to print helloworld is also able to write a code to calculate a combinatorial number. However, the calculati

BetaCZH的博客 813

Lucas求解组合数取模

Lucas定理求解组合数取模 Lucas定理 让我们先来了解一下Lucas定理。 Lucas定理是用来求C(n,m)%p(p为素数)的值: C(n,m)%p=(C(n%p,m%p)*C(n/p,m/p))%p 证明如下: C(n,m)的求解 了解了Lucas定理,我们只能将大组合数变成较小的组合数,但是,不能用这个定理化到最...

aiweiluan5095的博客 182

用位运算快速求解全部组合数

这个函数用来求C(n, k),其中comb就是二进制形式表示的子集,例如000111表示由后三个元素构成的组合或子集,并且该迭代过程可生成字典序递增的组合,这一特性非常有用。

大风车 872

组合数问题(复数快速幂, 组合数)

牛客 思路 参考题解, 众所周知组合数是满足二项式定理的, 这里有: (x+y)n=Cn0x0yn+Cn1xyn−1+...+Cnn−1xn−1y+Cnnxny0( x + y )^n = C _n^0 x_0 y _n + C _n^ 1 x y^ {n − 1} + . . . + C _n ^{n − 1} x_ {n − 1} y + C_ n^ n x _n y _0(x+y)n=Cn0​x0​yn​+Cn1​xyn−1+...+Cnn−1​xn−1​y+Cnn​xn​y0​ 考虑复数有 i1=

qq_45778406的博客 500

求大组合数模板

ll fac[maxn]; ll inv[maxn]; ll powmod(ll a, ll n) { ll res = 1; while(n) { if(n & 1) res = res * a % mod; n >>= 1; a = a * a % mod; } return res; } void init() { fac[0] = 1; for(int i = 1; i &

玛珈山大萌新 108

求组合数【递推+快速幂+卢卡斯+线性筛】

本篇文章将带你详细掌握求组合数的四种方法,层层递进,逐渐深入。

2402_88147924的博客 1393

快速求组合数

摘自https://www.jianshu.com/p/718a5ac26238 逆元+快速幂解法 (一)基本概念 上面两种方法都使用了递归方法,递归方法有个缺陷,就是在数据较大时效率较低。所以这里要介绍一个种新的求组合算法。在了解此算法之前,要先了解一些概念。 1 同余 同余是数论中的重要概念。 给定一个正整数m,如果两个整数a和b满足a-b能够被m整除,即(a-b)/m得到一个整数,那么就称整...

weixin_40136732的博客 6006
上一篇: 高考结束了以后应该做的事情(个人经历的总结)
下一篇: 第十四届蓝桥杯大赛软件赛省赛-试题 B---01 串的熵 解题思路+完整代码
ghost_him
博客等级 码龄6年 598粉丝 90原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值