快速幂+逆元求组合数

news2025/1/17 17:56:57

在计算组合数 C(n, k) = \frac{n!}{k!(n-k)!} 时,直接暴力计算既慢又容易溢出。今天我们来揭开 快速幂模逆元 的神秘面纱,带你一边学习理论,一边轻松解决实际问题!


什么是快速幂?

快速幂是一种高效计算 a^b \mod p 的方法。它利用指数的二进制表示,巧妙地减少了乘法次数,把原本复杂的幂运算大幅加速。

快速幂的原理

假设你要计算 a^b,比如 2^{13},可以写成:

2^{13} = 2^{8} \cdot 2^{4} \cdot 2^{1}

这里的 8,4,1 是 13 的二进制表示 1101。快速幂的核心思想就是通过分解指数,把幂运算拆分成多个平方和相乘的过程。

具体分解步骤如下:

  1. 如果指数 b 是奇数,取出当前底数 a 的值乘到结果中。
  2. 把底数 a 平方(相当于处理下一位二进制),指数 b 除以 2。
  3. 重复上述操作直到指数 b=0。

例如,计算 2^{13} \mod 1000

  • 13_{10} = 1101_2
  • 初始化:结果 = 1,底数 a=2,指数 b=13。
  • b = 1101_2
    • 1(奇数位):结果= 1 \times 2 = 2
    • 平方底数:a=4,指数 b=6。
  • b = 0110_2
    • 0(偶数位):跳过。
    • 平方底数:a=16,指数 b=3。
  • b = 0011_2
    • 1(奇数位):结果 = 2 \times 16 = 32
    • 平方底数:a=256,指数 b=1。
  • b = 0001_2
    • 1(奇数位):结果 = 32 \times 256 = 8192 \mod 1000 = 192

最终,答案是 2^{13} \mod 1000 = 192

快速幂代码

long long quickPow(long long a, long long b, long long mod) {
    long long res = 1;
    while (b > 0) {
        if (b % 2 == 1) { // 如果当前指数是奇数
            res = (res * a) % mod;
        }
        a = (a * a) % mod; // 平方底数
        b /= 2; // 指数减半
    }
    return res;
}

快速幂在组合数计算中的应用

在模数运算下,除法运算是一个大难题,而模逆元解决了这个问题。模逆元是 a 的「倒数」,满足:

a \cdot a^{-1} \equiv 1 \mod p

当 pp 是素数时,可以通过快速幂求出模逆元:

a^{-1} \equiv a^{p-2} \mod p

利用这一点,组合数公式:

C(n, k) = \frac{n!}{k!(n-k)!} \mod p

可以改写为:

C(n, k) = n! \cdot (k!)^{-1} \cdot ((n-k)!)^{-1} \mod p


代码实现

我们可以先预处理阶乘和逆元,再通过快速查询高效计算任意组合数。

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

const int MOD = 1e9 + 7;
const int MAXN = 1e5 + 5;

vector<long long> fact(MAXN); // 阶乘
vector<long long> invFact(MAXN); // 阶乘的逆元

// 快速幂
long long quickPow(long long a, long long b, long long mod) {
    long long res = 1;
    while (b > 0) {
        if (b % 2 == 1) {
            res = (res * a) % mod;
        }
        a = (a * a) % mod;
        b /= 2;
    }
    return res;
}

// 预处理阶乘和逆元
void precomputeFactorials(int n, long long mod) {
    fact[0] = 1;
    for (int i = 1; i <= n; i++) {
        fact[i] = fact[i - 1] * i % mod;
    }
    invFact[n] = quickPow(fact[n], mod - 2, mod);
    for (int i = n - 1; i >= 0; i--) {
        invFact[i] = invFact[i + 1] * (i + 1) % mod;
    }
}

// 计算组合数 C(n, k)
long long combination(int n, int k, long long mod) {
    if (k > n) return 0;
    return fact[n] * invFact[k] % mod * invFact[n - k] % mod;
}

int main() {
    precomputeFactorials(MAXN - 1, MOD);

    // 示例:计算组合数
    int n = 10, k = 3;
    cout << "C(" << n << ", " << k << ") = " << combination(n, k, MOD) << endl;

    return 0;
}

示例题目:多选问题

题目

你有 n=10道题,每道题可以选或不选(至少选 3 道)。问有多少种选择方法?

思路

  1. 总的选择数为2^{10}(每题都有选或不选两种可能)。
  2. 至少选 3 道的方案数为: \sum_{k=3}^{10} C(10, k) 我们需要用快速幂和组合数高效完成这个计算。

代码实现

int main() {
    precomputeFactorials(MAXN - 1, MOD);

    int n = 10, totalWays = quickPow(2, n, MOD);
    int atLeast3Ways = 0;

    for (int k = 3; k <= n; k++) {
        atLeast3Ways = (atLeast3Ways + combination(n, k, MOD)) % MOD;
    }

    cout << "至少选择 3 道题的方案数:" << atLeast3Ways << endl;
    return 0;
}

输出

至少选择 3 道题的方案数:1013

总结

通过快速幂的指数分解和模逆元的逆运算,我们轻松解决了组合数计算中的「模运算」难题。无论是科普练习还是竞赛题目,这套方法都是高效又实用的工具!快来试试,解锁你的数学超能力吧!🎉

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2256365.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

「OC」多线程(三)——NSOperation

「OC」多线程(三)——NSOperation 文章目录 「OC」多线程(三)——NSOperation前言介绍实现的具体步骤 NSOperation的创建NSOperationQueue的使用使用实例NSInvocationOperation的使用NSBlockOperation的使用NSOperationQueue的使用取消操作最大并发数 自定义NSOperation子类相关…

可供参考的GitHub国内镜像

在配置了本地hosts文件和魔法后仍存在无法访问的问题 针对如上问题&#xff0c;可以使用国内的镜像地址做替换 例如: https://github.com/bubbliiiing/detr-pytorch改成 https://hub.nuaa.cf/bubbliiiing/detr-pytorch推荐使用的镜像 https://hub.yzuu.cf/ https://hub.nua…

Codeforces Round 784 (Div. 4)

题目链接 A. Division? 题意 思路 模拟即可 示例代码 void solve() {int n;cin >> n;int ans;if(n > 1900) ans 1;else if(n > 1600) ans 2;else if(n > 1400) ans 3;else ans 4;cout << "Division " << ans << \n;}B. T…

E172 ASP.NET+SQL+C#+LW+图书管理系统的设计与实现 配置 源码 文档 全套资料

图书管理系统 1.项目摘要2. 系统的概述3.项目功能4.界面展示5.源码获取 1.项目摘要 摘 要 书籍是供人们获取并增长知识的主要途径&#xff0c;由于图书的种类较多&#xff0c;阅读者也较多&#xff0c;借阅量较大&#xff0c;且易出错&#xff0c;传统的图书借阅若还停留在手工…

TriCore架构-TC397将code从原来在P-Cache地址移到PSPR的地址,CPU的负载率为什么没影响

TC397有6个内核,每个核有自己的私有的Memory以及共有的Memory。 私有的:PSPR,DSPR,P-Cache,D-Cache,PF(X),LMU,DLMU,LPB PSPR主要用来运行RAM Code,比如说有些代码要放到RAM里面运行。 DSPR主要当成SRAM来用,比如用来存放全局变量。 P-Cache通过PFI接口访问DMU的3M内…

109.【C语言】数据结构之二叉树层序遍历

目录 1.知识回顾 2.代码实现 准备工作 LevelOrder函数 代码框架 关键代码 3.执行结果 1.知识回顾 层序遍历参见106.【C语言】数据结构之二叉树的三种递归遍历方式文章 截取的部分内容 定义:按层的方式遍历(,设n为树的深度,h1-->h2-->h3-->...-->hn) 以下面…

基于SpringBoot的养老院管理系统的设计与实现

一、前言 随着人口老龄化的加剧&#xff0c;养老院作为老年人养老的重要场所&#xff0c;其管理的高效性和科学性显得尤为重要。传统的养老院管理方式多依赖人工操作&#xff0c;存在信息记录不及时、不准确&#xff0c;管理流程繁琐&#xff0c;资源调配困难等问题。利用信息技…

012 路由信息协议RIP

路由信息协议RIP 作为度量(Metric)来衡量到达目的网络的距离 RIP是一种基于距离矢量D-V(Distance-Vector)算法的协议&#xff0c;它使用跳数(Hop Count)作为度量(Metric)来衡量到达目的网络的距离。 默认情况下&#xff0c;路由器到与它直接相连网络的跳数为0&#xff0c;因此…

NLP与LLM的工程化实践与学习思考 - 说说知识图谱

NLP与LLM的工程化实践与学习思考[24年半年工作总结] - 说说知识图谱 0 真的就是先说说1 为什么知识图谱什么是知识图谱&#xff1f;基于图的数据结构&#xff1f;基于数据结构的图&#xff1f;知识图谱的技术要点两个技术维度&#xff1a;知识、图七个技术要点&#xff1a;表示…

ROS2 - C++工程创建和工程解析

ROS2 系列文章目录 文章目录 ROS2 系列文章目录前言1. 安装构建工具colcon1.1 简介1.2 安装colcon 2. 创建工作空间2.1 创建一个工作目录 3 创建一个C软件包4. 编写发布者节点4.1 使用wget获取一个模板4.2 代码解读4.2 添加依赖项4.3 修改CmakeLists.txt 5. 编写订阅者节点5.1 …

【5G】架构 Architecture

5G网络架构受到了多个因素的影响。首先是为云端实现做好准备&#xff0c;其次是应对比之前更大的数据速率和更低的时延&#xff0c;启用新服务的能力&#xff0c;以及特别是在初期阶段与长期演进&#xff08;LTE&#xff09;的互操作需求。所有这些因素都对5G架构产生了影响。除…

vue2+html2canvas+js PDF实现试卷导出和打印功能

1.首先安装 import html2canvas from html2canvas; import { jsPDF } from jspdf; 2.引入打印插件print.js import Print from "/assets/js/print"; Vue.use(Print) // 打印类属性、方法定义 /* eslint-disable */ const Print function (dom, options) {if (…

图像滤波和卷积的不同及MATLAB应用实例

滤波与卷积在图像处理中都是非常重要的运算&#xff0c;但它们有着明显的区别。以下是滤波与卷积的主要不同点&#xff0c;并附带一个MATLAB实例来展示两者在图像处理中的效果差异。 一、滤波与卷积的不同 定义与目的&#xff1a; 1&#xff09;滤波&#xff1a;滤波是一种信…

Java集合(三)- Stack Queue

目录 一、Stack & Queue概述 1.1、Queue 1.2、Deque 二、方法剖析 2.1、addFirst() 2.2、addLast() 2.3、pollFirst() 2.4、pollLast() 2.5、peekFirst() 2.6、peekLast() 一、Stack & Queue概述 Java里有一个叫做Stack的类&#xff0c;却没有叫做Queue的类…

数据结构理论

内容来源青岛大学数据结构与算法课程&#xff0c;链接&#xff1a;数据结构与算法基础&#xff08;青岛大学-王卓&#xff09;_哔哩哔哩_bilibili 绪论 数据结构概述 数据结构和算法的定义&#xff1a;我们如何把现实中大量而复杂的问题以特定的数据类型和特定的存储结构保存…

008.精读《Apache Paimon Docs - Table w/o PK》

文章目录 1. 引言2. 基本概念2.1 定义2.2 使用场景 3. 流式处理3.1 自动小文件合并3.2 流式查询 4. 数据更新4.1 查询4.2 更新4.3 分桶附加表 5 总结 1. 引言 通过本文&#xff0c;上篇我们了解了Apache Paimon 主键表&#xff0c;本期我们将继续学习附加表&#xff08;Append…

硬件选型规则

光源选型: 先用型号中带H的&#xff0c;没有的选标准的. 光源和光源控制器的搭配需要确保接口一致。 根据型号表中的最佳工作距离和相机的尺寸。 光源控制器选型&#xff1a; 首先选择海康风格系列光源控制器考虑与光源的接口匹配。功率应该满足接近光源功率。检查是否退市…

数据分析系列---requests的使用

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 主环境和虚拟环境 主环境是电脑上安装的python环境 虚拟环境在项目中可以实现环境的隔离&#xff0c;假设DemoA和DemoB分别用到了某个三方库1.0和2.0版本&#xff0c;那么在一个…

selenium常见接口函数使用

博客主页&#xff1a;花果山~程序猿-CSDN博客 文章分栏&#xff1a;测试_花果山~程序猿的博客-CSDN博客 关注我一起学习&#xff0c;一起进步&#xff0c;一起探索编程的无限可能吧&#xff01;让我们一起努力&#xff0c;一起成长&#xff01; 目录 1. 查找 查找方式 css_s…

深度学习之预备知识

深度学习是关于优化的学习。对一个带有参数的模型&#xff0c;找到其中能拟合数据最好的模型。 一、数据操作 张量&#xff1a;表示一个由数值组成的数组&#xff0c;这个数组可能有多个维度。具有一个轴的张量对应数学上的向量&#xff0c;具有两个轴的张量对应数学上的矩阵&…