当前位置: 首页 > news >正文

领略算法真谛:求组合数

嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的
passion。准备好和我一起冲进代码的奇幻宇宙了吗?Let’s go!

请添加图片描述

我的博客:yuanManGan

我的专栏:C++入门小馆 C言雅韵集 数据结构漫游记 闲言碎语小记坊 进阶数据结构 走进Linux的世界 题山采玉 领略算法真谛

在这里插入图片描述


求组合数


先来回归一下高中知识:
从 n 个不同的元素中,任取 m 个元素排成⼀列。所有取法的个数就是排列数,记作 AnmA_n^mAnm
在这里插入图片描述

Anm=n!(n−m)!=n⋅(n−1)⋅(n−2)⋅⋯⋅(n−m+1)A_n^m = \frac{n!}{(n - m)!} = n \cdot (n - 1) \cdot (n - 2) \cdot \dots \cdot (n - m + 1)Anm=(nm)!n!=n(n1)(n2)(nm+1)

从 n 个不同的元素中,任取 m 个元素。所有取法的个数就是组合数,记作 CnmC_n^mCnm
在这里插入图片描述
Cnm=n!m!⋅(n−m)!=n×(n−1)×(n−2)×⋯×(n−m+1)m×(m−1)×(m−2)×⋯×2×1C_n^m = \frac{n!}{m! \cdot (n - m)!} = \frac{n \times (n - 1) \times (n - 2) \times \dots \times (n - m + 1)}{m \times (m - 1) \times (m - 2) \times \dots \times 2 \times 1} \quad \text{} Cnm=m!(nm)!n!=m×(m1)×(m2)××2×1n×(n1)×(n2)××(nm+1)
下面就来写写几种求组合数的方法吧!


方法一循环


问题:单次查询 CnmmodpC_n^m\mod pCnmmodp(其中 1≤n≤1061 \leq n \leq 10^61n106ppp 为质数且 p>np > np>n

查询: O(m)

直接用公式循环求解即可,注意m!要使用逆元

#include<iostream>
using namespace std;typedef long long LL;
//快速幂
LL qpow(LL a, LL b, LL p)
{LL ret = 1;while (b){if (b & 1) ret = ret * a % p;a = a * a % p;b >>= 1;		}return ret;
}
LL C(int n, int m, int p)
{LL up = 1, down = 1;for (int i = n; i >= n - m + 1; i--) up = up * i % p;for (int i = 2; i <= m; i++) down = down * i % p;return up * qpow(down, p - 2, p) % p;
}
int main()
{cout << C(4, 2, 9) << endl;return 0;
}

方法二 杨辉三角


0 ⾏: 1
1 ⾏: 1 1
2 ⾏: 1 2 1
3 ⾏: 1 3 3 1
4 ⾏: 1 4 6 4 1
其中第 i ⾏就是 n = i 展开后的各项系数。
通过杨辉三⻆可以得出⼀个公式:
Cnk=Cn−1k−1+Cn−1kC_n^k = C_{n-1}^{k-1} + C_{n-1}^kCnk=Cn1k1+Cn1k

const int N = 2e3 + 10;
int n, p = 1001;
LL f[N][N];
void get_c()
{for (int i = 0; i <= N; i++){f[i][0] = 1;for (int j = 1; j <= i; j++){f[i][j] = (f[i - 1][j - 1] + f[i - 1][j]) % p;}}
}
int main()
{get_c();cout << f[3][2] << endl;return 0;
}

方式三阶乘以及阶乘逆元表 + 公式


多次查询CnmmodpC_n^m \mod pCnmmodp 1≤n≤1061 \leq n \leq 10^61n106 q≤106q \leq 10^6q106 p 为质数且大于 n。

数据量过⼤,⽤杨辉三⻆打表会超时并且超空间。

• 此时考虑使⽤公式直接计算。
Cnm=n!(n−m)!⋅m!C_n^m = \frac{n!}{(n - m)! \cdot m!} Cnm=(nm)!m!n!
• 只要能够将所有的阶乘,以及阶乘的逆元全部存在两个数组中,那么仅需在两个表中拿出相应的值
即可。

我们需要打几个表

打表所有的阶乘:
​f[i] 表⽰ i 的阶乘 mod p 的值,f[i] = f[i − 1] × i
这样,从左往右递推⼀遍,就可以把所有的阶乘全部维护出来。

打表所有的阶乘的逆元:
用 ( g[i] ) 表示 ( i ) 的阶乘模 ( p ) 的值的逆元,即:

g[i]=(i×(i−1)×⋯×1)−1modpg[i] = \left( i \times (i-1) \times \dots \times 1 \right)^{-1} \mod p g[i]=(i×(i1)××1)1modp
g[i−1]=(i×(i−1)×⋯×1)−1×imodpg[i-1] = \left( i \times (i-1) \times \dots \times 1 \right)^{-1} \times i \mod p g[i1]=(i×(i1)××1)1×imodp
推出来
g[i−1]=g[i]×imodpg[i-1] =g[i]\times i \mod p g[i1]=g[i]×imodp
这样,从右往左递推⼀遍,就可以把所有阶乘的逆元维护出来。

const int N = 1e6 + 10;int n, p;
LL f[N], g[N];
void init()
{f[0] = 1;for (int i = 1; i <= N; i++) f[i] = f[i - 1] * i % p;g[n] = qpow(f[n], p - 2, p);for (int i = n - 1; i >= 0; i--) g[i] = g[i + 1] * (i + 1) % p;
}
LL C(int n, int m)
{if (n < m) return 0;return f[n] * g[n - m] % p * g[m] % p;
}
int main()
{return 0;
}

方式四卢卡斯定理


问题:多次查询CnmmodpC_n^m \mod pCnmmodp ,其中1≤n≤10181 \leq n \leq 10^{18}1n1018,只保证p≤10p \leq 10p10且是质数,也就是ppp有可能小于nnn

我们只需要记住这个公式即可

卢卡斯定理

对于组合数CnmmodpC_n^m \mod pCnmmodp (其中模数 ( p ) 为质数),有如下递归关系:
Cnm≡C⌊np⌋⌊mp⌋×Cnmodpmmodp(modp)C_n^m \equiv C_{\left\lfloor \frac{n}{p} \right\rfloor}^{\left\lfloor \frac{m}{p} \right\rfloor} \times C_{n \mod p}^{m \mod p} \pmod{p}CnmCpnpm×Cnmodpmmodp(modp)

const int N = 1e6 + 10;int n, p;
LL f[N], g[N];
void init()
{f[0] = 1;for (int i = 1; i <= N; i++) f[i] = f[i - 1] * i % p;g[n] = qpow(f[n], p - 2, p);for (int i = n - 1; i >= 0; i--) g[i] = g[i + 1] * (i + 1) % p;
}
LL C(int n, int m, int p)
{if (n < m) return 0;return f[n] * g[n - m] % p * g[m] % p;
}
LL lucas(LL n, LL m, LL p)
{if (m == 0) return 1;return lucas(n / p, m / p, p) * C(n % p, m % p, p) % p;
}
int main()
{return 0;
}

在这里插入图片描述

http://www.dtcms.com/a/474846.html

相关文章:

  • 企业网站建设费用会计科目哪些网站可以免费看剧
  • 自己做单词卡的网站是什么广州市外贸网站建设品牌
  • 【强化学习】#10 Actor-Critic:从QAC到A3C/A2C
  • 存储栈学习笔记
  • 廊坊网站快速排名优化域名更换网站
  • 个人网站制作程序南昌地宝网租房信息网
  • 一流的龙岗网站设计内网建设网站
  • 大连网站建设服务东莞营销网站建设价格
  • 外贸网站做多少钱的4399影视在线观看免费高清
  • 网站层级关系装修平台网站有哪些
  • 【完整源码+数据集+部署教程】 落叶植物叶片分类系统源码和数据集:改进yolo11-LVMB
  • 公司网站宣传设计方案本地最新招聘信息
  • 茶叶网站flash模板免费下载wordpress开发的网站有哪些
  • wordpress ajax 注册个人做seo怎么赚钱
  • seata原理源码分析(二)事务模式-TCC(一) 织入拦截器,rpc,资源分析
  • 网站建设创意广告苏州北京网站建设
  • TwinCAT3配置OPC UA Server过程总结
  • 做网站需要用什么软件百度商店应用市场
  • 以Copilot重构CRUD流程为例
  • 网站备案证书放到哪里网站需要服务器
  • 【网络工程师】企业网络骨干链路冗余与环路避免实践
  • MATLAB双缝干涉实验模拟程序
  • 做网站现在用什么语言长沙seo网络优化
  • 创建对象内存分析
  • linux学习——总结
  • 上海网站搜索引擎优化如何搭建网站建设环境
  • 词根学习笔记 | Ag系列
  • IMX6ULL学习笔记_Boot和裸机篇(6)--- IMX6ULL简单SHELL以及SEGGER ES的Printf和字节对齐问题
  • 《C++二叉引擎:STL风格搜索树实现与算法优化》
  • 营销网站售后调查百度竞价调价软件