如何快速计算65题中65的逆元?
摘要:65.Acwing基础课第876题-简单-快速幂求逆元 题目描述 (给定 n 组 ai,pi,其中 pi 是质数,求 ai 模 pi 的乘法逆元,若逆元不存在则输出 impossible)。 注意:(请返回在 0∼p−1 之间的逆元
65.Acwing基础课第876题-简单-快速幂求逆元
题目描述
\(给定 n 组 ai,pi,其中 pi 是质数,求 ai 模 pi 的乘法逆元,若逆元不存在则输出 impossible\)。
注意:\(请返回在 0∼p−1 之间的逆元\)。
乘法逆元的定义
若整数 \(b, m\) 互质,并且对于任意的整数 \(a\),如果满足 \(b|a\),则存在一个整数 \(x\),使得 \(\frac{a}{b} \equiv x \times x \pmod{m}\) ,称 \(x\) 为 \(b\) 的模 \(m\) 乘法逆元,记为 \(b^{-1} \pmod{m}\)。
\(b\) 存在乘法逆元的充要条件是 \(b\) 与模数 \(m\) 互质。当模数 \(m\) 为质数时,\(b^{m-2}\) 即为 \(b\) 的乘法逆元。
输入格式
\(第一行包含整数 n\)。
\(接下来 n 行,每行包含三个整数 a_i,p_i,数据保证 p_i 是质数\)。
输出格式
\(输出共 n 行,每组数据输出一个结果,每个结果占一行\)。
\(若 a_i 模 p_i 的乘法逆元存在,则输出一个整数,表示逆元,否则输出 impossible\)。
数据范围
\(1≤n≤10^5\),
\(1≤a_i,p_i≤2×10^9\)
输入样例:
3
4 3
8 5
6 3
输出样例:
1
2
impossible
代码:
// 包含输入输出流头文件(cin/cout依赖,本代码用C风格IO,保留作为通用模板)
#include <iostream>
#include <algorithm>
using namespace std;
// 定义长整型别名:防止乘法过程中溢出(int相乘可能超出int范围)
typedef long long LL;
// 快速幂核心函数:计算 (a^b) % p 的结果
// 用途:本题中用于计算费马小定理的 b^(p-2) mod p(乘法逆元)
// 参数:a-底数,b-指数,p-模数(本题中p是质数)
LL qmi(int a, int b, int p)
{
LL res = 1; // 初始化结果为1(乘法单位元)
// 二进制分解指数b,循环处理每一位(时间复杂度O(logb))
while (b)
{
// b & 1:判断b的二进制最低位是否为1(等价于b%2==1)
// 若为1,将当前底数的幂乘到结果中,并取模防止溢出
if (b & 1) res = res * a % p;
// 底数平方:对应指数左移一位(如a^1→a^2,a^2→a^4)
// (LL)a:强制转换为长整型,避免a*a溢出int范围(如a=1e9时,a²=1e18)
a = a * (LL)a % p;
// 指数右移一位:等价于b = b / 2,舍弃已处理的最低位
b >>= 1;
}
return res; // 返回 (a^b) % p 的结果
}
int main()
{
int n; // n:测试用例的组数
// C风格输入:比cin更快,适合竞赛大数据量场景
scanf("%d", &n);
// 循环处理n组测试用例
while (n -- )
{
int a, p; // a:要求逆元的数;p:模数(题目保证p是质数)
scanf("%d%d", &a, &p);
// 乘法逆元存在的充要条件:a与p互质(p是质数时,等价于a%p≠0)
if (a % p == 0)
puts("impossible"); // a是p的倍数,无逆元,输出impossible
else
// 费马小定理:当p是质数且a与p互质时,a的乘法逆元 = a^(p-2) mod p
printf("%lld\n", qmi(a, p - 2, p));
}
return 0; // 程序正常结束
}
