快速幂求逆元【通俗易懂 + 无需任何前置知识 + 不懂你打我】

题目:

给定 n 组 ai,pi,其中 pi 是质数,求 ai 模 pi 的乘法逆元,若逆元不存在则输出 impossible。

注意:请返回在 0∼p−1 之间的逆元。乘法逆元的定义若整数 b,m 互质,并且对于任意的整数 a,如果满足 b|a,则存在一个整数 x,使得 a/b≡a×x(modm),则称 x 为 b 的模 m 乘法逆元,记为 b−1(mod m)。b 存在乘法逆元的充要条件是 b 与模数 m 互质。当模数 m 为质数时,bm−2 即为 b 的乘法逆元。

输入格式
第一行包含整数 n。
接下来 n 行,每行包含一个数组 ai,pi,数据保证 pi 是质数。

输出格式
输出共 n 行,每组数据输出一个结果,每个结果占一行。
若 ai 模 pi 的乘法逆元存在,则输出一个整数,表示逆元,否则输出 impossible。

数据范围
1≤n≤105,
1≤ai,pi≤2∗109

思路:

在这里插入图片描述

这是逆元的本质:(可看可不看!) 逆元的定义: 假设 a 除
b,且a和b都是整数,非浮点数,那么我们希望不做除法,因为取余数的话除法很麻烦,所以我们希望把除法变成乘法,希望找到一个数,使得a/b的余数 == ax%m。 即对于某一个b,我们能够找到一个数x,使得a/b和ax模m的余数相同的话, 则把x记作b的模m的逆元,记作b的-1次方; 即b的逆元, b的-1次方,是一个整数,是一个标记。即我们可以把所有a/b的情况转化为a*b的逆元的情况下 % M;即把除法变成了整数。
在这里插入图片描述

  1. 首先我们要明白什么是逆元?
    对于求某个数的逆元,实际上就是求一个数x,这个x能够使得 该数a,模上一个 p ,余数为1,即原本的 a%p != 1,而找到一个数x,使得:ax % p == 1;就是这样的场景!
    本题给定的恰好就是一个数a,一个数p,让求 a%p的逆元,即求一个数x使得a
    x后余数为1,%p==1;
    即可得:=》 a*x % p = = 1;
  2. 弄清楚本题的求解目标和逆元之后,我们应该思考如何去找x呢?如何去枚举?
    首先排除暴力枚举,因为一共n组测试数据,n最大可以取到1e5;而逆元的范围可能是:0~p-1之间,p最大取到:2*1e9;所以说这里高时间复杂度就往公式想!
  3. 题目中给定的已知条件 p 是质数,而对于一个数a,与质数取模,要么%p == 0,即为p的倍数,一旦a是p的倍数,那就输出 ”impossible“;反之 %p != 0的话,则该数一定与p互质。
  4. 由费马定理可知:如果两个数是互质,一个数为a,一个数为p,则 ap-1 % p == 1;
    那么我们再提出一个a:a*ap-2 % p = = 1 ;所以说 a % p中,a的逆元就是ap-2

** 草稿: **
所以实际上本题就是给我一个b,然后让我找到一个x,使得bx % m 同余于1就可以了!
即找到一个x,使得b
x的乘积mod m 等于 1;
如果b是p的倍数,则b*x也一定是p的倍数,则模p一定不等于1的,就无解,若b不是p的倍数,那么由于p是质数,所以b只能是和p互质的,然后由费马定理可得b^p-1一定模p==1;一定存在逆元。
在这里插入图片描述

代码:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;

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

int main()
{
    int n;
    cin >> n;
    
    while (n -- )
    {
        int a, p;
        cin >> a >> p;
        
        int x = quick_power(a, p-2, p); //直接求出逆元的值!
        if (a%p) cout << x << endl;
        else puts("impossible");
    }
    return 0;
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值