【C++】 排列与组合算法详解(进阶篇)

news/2024/12/29 5:09:01/

f4e0159841ab450d861dde9e8fb5ba0d.gif

写在前面

我上次发了一篇题解:C++排列与组合算法详解
最开始,我是抱着水题解的想法写的,但却成为了阅读量 最高 的文章,没有之一。

所以今天咱们来重制一篇文章,介绍几个进阶优化版的算法。


算法1:朴素算法

思路

具体见 C++排列与组合算法详解

缺点

不能将结果取模,因为朴素的组合公式在取模意义下没用。


算法2:递推预处理

思路

我们发现:
C a 0 = 1 C a b = C a − 1 b + C a − 1 b − 1 ( a , b > 0 ) C_a^0 = 1\\ C_a^b=C_{a-1}^b+C_{a-1}^{b-1}(a,b>0) Ca0=1Cab=Ca1b+Ca1b1(a,b>0)

所以我们可以写一个递推函数(部分非主要内容已省略):

void init_C()
{for (int i = 0; i < N; i ++ ) // N 表示预处理最大的下标for (int j = 0; j <= i; j ++ )if (!j) c[i][j] = 1;else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % P;
}

再预处理阶乘:

void f(int n)
{f[0] = 1;for (int i = 1; i <= n; i ++ )f[i] = (LL)f[i - 1] * i % P;
}

需要排列的话还可以预处理排列:

void init_A(int n)
{for (int i = 0; i <= n; i ++ )for (int j = 0; j <= i; j ++ )a[i][j] = (LL)f[i - j] * c[i][j] % P;
}
时间复杂度: O ( n 2 ) O(n^2) O(n2)

可以处理 5000 5000 5000 以内规模的数据


算法3:阶乘逆元

思路

根据费马小定理可得,当 p p p 为质数时, a p − 1 ≡ 1 ( m o d p ) a^{p-1} \equiv 1\pmod p ap11(modp)
∴ a p − 2 ≡ 1 a ( m o d p ) \therefore a^{p-2} \equiv \frac{1}{a}\pmod p ap2a1(modp)
这就是乘法逆元,通常使用在需要除法取模的情况。

这里再次提一下排列、组合公式: C a b = a ! b ! ( a − b ) ! , A a b = a ! b ! C_a^b=\frac{a!}{b!(a-b)!},\ \ A_a^b=\frac{a!}{b!} Cab=b!(ab)!a!,  Aab=b!a!

求逆元需要用到快速幂:

LL qpow(LL a, LL b, LL p)
{LL res = 1;while (b){if (b & 1) res = res * a % p;b >>= 1;a = a * a % p;}return res;
}

然后预处理阶乘和阶乘逆元:

f[0] = uf[0] = 1;
for (int i = 1; i < N; i ++ )
{f[i] = (LL)f[i - 1] * i % mod;uf[i] = (LL)uf[i - 1] * qpow(i, mod - 2, mod) % mod;
}

同样的,如果输出排列、组合结果的话需要利用公式。

时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn)

可以处理 1 0 5 10^5 105 以内规模的数据

思考:读者也可以尝试写 O ( n ) O(n) O(n) 预处理阶乘逆元。

算法4:Lucas 定理

思路

由 Lucas 定理可得:当 p p p 为质数时,

C a b = C a p b p × C a m o d p b m o d p \large{C_a^b=C_{\frac{a}{p}}^{\frac{b}{p}} \times C_{a \bmod p}^{b \bmod p}} Cab=Cpapb×Camodpbmodp

因此,我们可以写一个递归函数 LL lucas(int a, int b),递归出口是 a k < p , b k < p a_k<p, b_k<p ak<p,bk<p

递归的过程相当于自上向下将 C a 1 b 1 , C a 2 b 2 , … , C a k b k C_{a_1}^{b_1},C_{a_2}^{b_2},…,C_{a_k}^{b_k} Ca1b1,Ca2b2,,Cakbk 添加到乘式里。

LL lucas(LL a, LL b)
{if (a < p && b < p) return C(a, b);return (LL)C(a % p, b % p) * lucas(a / p, b / p) % p;
}

这里面的 C(a, b) 是指 算法3 ,即用阶乘和阶乘逆元求组合数。

LL qpow(LL a, LL b, LL p)
{int res = 1;while (b){if (b & 1) res = res * a % p;b >>= 1;a = a * a % p;}return res;
}LL C(LL a, LL b)
{LL res = 1;for (int i = 1, j = a; i <= b; i ++ , j -- ){res = (LL)res * j % p;res = (LL) res * qpow(i, p - 2, p) % p;}return res;
}

同样的,如果输出排列、组合结果的话需要利用公式。

时间复杂度: O ( p × log ⁡ p n ) O(p \times \log_p n) O(p×logpn)

可以处理 a , b ≤ 1 0 18 , p ≤ 1 0 5 a,b \le 10^{18},p \le 10^5 a,b1018,p105 以内规模的数据


228aa7bed3e021faf24cf8560d3e47bb.gif

最后,如果觉得对您有帮助的话,点个赞再走吧!


http://www.ppmy.cn/news/74972.html

相关文章

一文读懂selenium自动化测试(基于Python)

前言 我们今天来聊聊selenium自动化测试&#xff0c;我们都知道selenium是一款web自动化测试的工具&#xff0c;它应该如何去运用呢?我们接着看下去。 ​1、Selenium简介&#xff1a; 1.1 Selenium&#xff1a; Selenium是一款主要用于Web应用程序自动化测试的工具集合。Sele…

CTF必看~ PHP反序列化漏洞6:绝妙_wakeup绕过技巧

作者&#xff1a;Eason_LYC 悲观者预言失败&#xff0c;十言九中。 乐观者创造奇迹&#xff0c;一次即可。 一个人的价值&#xff0c;在于他所拥有的。可以不学无术&#xff0c;但不能一无所有&#xff01; 技术领域&#xff1a;WEB安全、网络攻防 关注WEB安全、网络攻防。我的…

RocketMQ学习

各MQ 并发性能比较 吞吐量 kafka 17.3w/s rocketMQ 11.6w/s RabbitMQ 5.96w/s RocketMQ组件 broker 核心业务组件 nameServe 保存broker 的ip、端口、上下线信息等。 类似注册中心 启动nameServe 时会调用 runserver 启动broker &#xff0c;会默认读取/conf/broker.conf …

Netty实战(七)

EventLoop和线程模型 一、什么是线程模型二、EventLoop 接口2.14 Netty 4 中的 I/O 和事件处理 三、任务调度3.1 JDK 的任务调度 API3.2 使用 EventLoop 调度任务 四、实现细节4.1 线程管理4.2 EventLoop/线程的分配4.2.1 异步传输4.2.2 &#xff0e;阻塞传输 一、什么是线程模…

Linux(云计算)期末复习资料

1&#xff1a;linux概述 ​ Linux是一种自由、开放源代码的操作系统&#xff0c;它最初由芬兰的Linus Torvalds在1991年开发&#xff0c;目前已经成为世界上最流行的操作系统之一。Linux操作系统的特点是免费、稳定、安全、可定制、可移植性强、支持多任务、多用户等。 2&…

什么是半实物仿真平台自动驾驶半实物仿真平台有哪些?

文章目录 半实物仿真平台介绍自动驾驶半实物仿真平台介绍1.CARLA2.AirSim3.LGSVL Simulator 半实物仿真平台介绍 半实物仿真平台是一种综合利用虚拟仿真和实际硬件设备的仿真系统。它将虚拟环境和真实硬件设备结合起来&#xff0c;旨在提供更真实、更准确的仿真体验。 在半实…

Centos7单机部署Flink13.6及测试FinkCDC同步MySQL

一、背景 公司CDH6.3.2里面的版本是Flink1.12.0。而因为FlinkCDC2.0.0只支持Flink1.13.0以后&#xff0c;版本不匹配&#xff0c;所以只能升级版本。但是升级版本是个大工程&#xff0c;要编译、要parcel制作工具&#xff0c;而且是生产环境的升级&#xff0c;没办法因为要测试…

ubuntu中安装autogpt,python虚拟环境安装使用

ubuntu中安装autogpt&#xff0c;python虚拟环境安装使用 git安装 https://gitforwindows.org python3.10安装&#xff1a; autogpt支持python版本是3.10&#xff0c;ubuntu20.04中默认版本3.8是不支持的。 安装虚拟环境 sudo add-apt-repository ppa:deadsnakes/ppa sudo…