数论·快速幂和逆元

文章目录

快速幂: O ( log ⁡ b ) O(\log b) O(logb)

875. 快速幂

数学定义

目标函数: a b m o d p a^b mod p abmodp

其中a,b,p的值都非常大(1e9+)

快速幂是一种用来高效计算幂 的方法。

如果直接计算 a b a^b ab,需要做 b − 1 b-1 b−1 次乘法,时间复杂度是 O ( b ) O(b) O(b);

而快速幂利用指数的二进制拆分性质 ,可以把时间复杂度降为 O ( log ⁡ b ) O(\log b) O(logb)。

数学原理

任意整数 b b b 都可以写成二进制形式:
b = ∑ i = 0 k c i 2 i ( c i ∈ 0 , 1 ) b = \sum_{i=0}^{k} c_i 2^i \quad (c_i \in {0,1}) b=∑i=0kci2i(ci∈0,1)

因此,

a b = a ∑ c i 2 i = ∏ i = 0 k a c i 2 i a^b = a^{\sum c_i 2^i} = \prod_{i=0}^{k} a^{c_i 2^i} ab=a∑ci2i=∏i=0kaci2i

因为 c i c_i ci 只可能是 0 0 0 或 1 1 1,所以实际上只需要把那些二进制位上为 1 1 1 的幂乘起来即可。

例如若

b = 13 = ( 1101 ) 2 = 8 + 4 + 1 b = 13 = (1101)_2 = 8 + 4 + 1 b=13=(1101)2=8+4+1

那么

a 13 = a 8 ⋅ a 4 ⋅ a 1 a^{13} = a^8 \cdot a^4 \cdot a^1 a13=a8⋅a4⋅a1

这就是快速幂的本质:

实现

代码中用了三个变量:

  • pow:当前底数,表示当前处理到的幂次
  • res:当前答案
  • b:指数,每次右移一位
  • 注意:一定要开long long!!!一定要开long long!!!一定要开long long!!!
cpp 复制代码
ll qmi(int a, int b, int p) {
	ll pow = a, res = 1;
	while (b) {
		if (b & 1) {
			res = res * pow % p;
		}
		pow = pow * pow % p;
		b = b >> 1;
	}
	return res;
}

逆元

876. 快速幂求逆元

数学定义

对于整数 a a a 和模数 p p p,如果存在整数 x x x,使得

a ⋅ x ≡ 1 ( m o d p ) a \cdot x \equiv 1 \pmod{p} a⋅x≡1(modp)

则称 x x x 是 a a a 在模 p p p 意义下的乘法逆元 (简称逆元),记作:

a − 1 ≡ x ( m o d p ) a^{-1} \equiv x \pmod{p} a−1≡x(modp)

存在条件:

gcd ⁡ ( a , p ) = 1 \gcd(a, p) = 1 gcd(a,p)=1

否则逆元不存在。


费马小定理

定理内容

若 p p p 是质数,且 gcd ⁡ ( a , p ) = 1 \gcd(a,p)=1 gcd(a,p)=1,则:

a p − 1 ≡ 1 ( m o d p ) a^{p-1} \equiv 1 \pmod{p} ap−1≡1(modp)

失效条件

费马小定理及其逆元形式必须满足以下条件

  1. p p p 必须是质数
  2. a ≢ 0 ( m o d p ) a \not\equiv 0 \pmod{p} a≡0(modp)(即 gcd ⁡ ( a , p ) = 1 \gcd(a,p)=1 gcd(a,p)=1)

若不满足:

  • 当 p p p 不是质数 → 公式不成立
  • 当 a ≡ 0 ( m o d p ) a \equiv 0 \pmod{p} a≡0(modp) → 逆元不存在

快速幂求逆元: O ( log ⁡ p ) O(\log p) O(logp)

数学原理

基于公式:

a − 1 ≡ a p − 2 ( m o d p ) a^{-1} \equiv a^{p-2} \pmod{p} a−1≡ap−2(modp)

  1. 判断是否存在逆元

    • 若 a ≡ 0 ( m o d p ) a \equiv 0 \pmod{p} a≡0(modp),输出 "impossible"
  2. 转化为幂运算

    • 将问题转化为计算:

      a p − 2   m o d   p a^{p-2} \bmod p ap−2modp

cpp 复制代码
ll qmi(int a, int b, int p) {
	ll res = 1, pow = a;
	while (b) {
		if (b & 1) {
			res = res * pow % p;
		}
		b >>= 1;
		pow = pow * pow% p;
	}
	return res;
}
void solve() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		int a, p;
		cin >> a >>  p;
		if (a % p) {
			cout << qmi(a, p - 2, p) << endl;
		}
		else {
			cout << "impossible" << endl;
		}
	}
}
相关推荐
小玮看世界33 分钟前
[Python]OD算法在OD实际运用转化参考清单
开发语言·python·算法
黎阳之光37 分钟前
数字孪生赋能全域水网,实现水资源管控与节水降碳双向提升
人工智能·物联网·算法·安全·数字孪生
随意起个昵称1 小时前
【BFS】冰面滑行
算法·宽度优先
(Charon)2 小时前
【C++】定时器进阶:使用最小堆管理定时任务
c++·算法
hansang_IR2 小时前
【题解】 [省选联考 2021 A/B 卷] 卡牌游戏
c++·算法
这个DBA有点耶3 小时前
COUNT慢不是因为用了*,是这5个原因——1000万行数据实测+执行计划深度解析
数据库·mysql·算法
贾伟康3 小时前
【口算王|01】HarmonyOS ArkTS 口算题生成实战:按年级、运算类型和难度生成可控题目
算法·harmonyos·arkts·随机生成·口算题
lzx_0023 小时前
C++11(一)
开发语言·c++·算法
529宝宝起名网3 小时前
用 Python 实现名字寓意评分算法:基于 NLP 语义分析的名字内涵深度评估
python·算法·自然语言处理
带多刺的玫瑰4 小时前
Leecode#26刷题之删除有序数组中的重复项
数据结构·算法·leetcode