快速幂和应用快速幂求逆元

快速幂

1.基础的快速幂

​ 对于快速幂问题 之前的解决方法是逐步合并 ,比如 4 5 4^5 45我们可以先变成 1 6 2 ∗ 4 16^2*4 1624,然后再变成 256 ∗ 4 256*4 2564,但是这样有一个缺点就是代码很容易写错,然后学习到了一种新的求解快速幂的方法。

​ 首先为什么要引进快速幂,如果我们要求 4 n 4^n 4n,那么我们暴力的做法就是写个for循环 但是 这样的时间复杂度是 O ( n ) O(n) O(n)的 时间复杂度太高了 ,因此,我们要引进快速幂 。

​ 首先,整一些先导知识,第一,就是二进制,我们知道,对于任意一个10进制的数,都能用二进制来表示(不然计算机就无法运行了),那么接下来就简单了 可以看以下公式
4 5 = 4 2 1 ∗ 4 2 2 ( 1 ) 4^5=4^{2^1}*4^{2^2} (1) 45=421422(1)
​ 也就是说,对于求幂运算的指数,我们可以把它转化为2进制去进行计算,也就是说,而且,我们可以观察到 4 2 1 4^{2^1} 421 4 2 2 4^{2^2} 422,我们只需要把 4 2 1 4^{2^1} 421 平方即可,这样我们就可以求快速幂了 。下面直接进入coding可能好理解一点。

​ coding:

#include<iostream>
using namespace std;
int n;
typedef long long int LL;
LL qmi(int a,int b,int p)
{
    // 求解 a^b%p的结果
    LL res=1;
    int k=b;
    while(k!=0)
    {
        // 如果k这个数二进制表示最后一位是1 也就是这一位
        if(k&1)
        {
            res=res*a%p;

        }
        // 左移一位看看下一位是不是1
        k=k>>1;
        a=a*(LL)a%p;

        // cout<<k<<endl;
    }
   
    return res;


}
int main()
{
    cin>>n;
    while(n--)
    {
        int a,b,p;
        cin>>a>>b>>p;
        cout<<qmi(a,b,p)<<endl;



    }


    return 0;
}

​ 注意,在代码当中 我们是按照公式(1)把我们的结果拆成了 4 2 k 4^{2^k} 42k 相乘 也就是把系数b转化为了2进制

​ 注意,我们的求解ans和不断平方a以得到a的更高次方是一个同时的过程

​ 而这个代码的时间复杂度是 ( l o g 2 n ) (log_2n) (log2n)的 是可以接受的 。

2.快速幂求解逆元

​ 什么是逆元 概念很抽象 这里可以这么理解
a ÷ b ≡ a ∗ x (   m o d   m ) ( 2 ) a\div b \equiv a*x(\ mod\ m) (2) a÷bax( mod m)2

​ 就是如果b|a 那么 a ÷ b a\div b a÷b就一定是一个整数(废话),但是,对于除法,我们感觉是很麻烦的 因此 我们是不是转换为乘法那,于是,我们就想到了逆元 如果满足公式(2) 那么我们就把x叫做b的模m乘法逆元 其中b与m必须是互质的

​ 我们可以把公式(2)改写一下 令x等于 b − 1 b^{-1} b1

​ 方程两边乘b
a ≡ a ∗ b − 1 ∗ b ( m o d   p ) a \equiv a*b^{-1}*b(mod\ p) aab1b(mod p)
​ 消除两边的a
b ∗ b − 1 ≡ 1 ( m o d   p ) b*b^{-1}\equiv 1(mod\ p) bb11(mod p)
然后根据费马小引理: 如果p是一个质数 a不是p的倍数 也就是a和p互质 那么 a p − 1 = 1 ( m o d   p ) a^{p-1}=1(mod\ p) ap1=1(mod p)

那么我们最后的式子可以改写为 b ∗ b p − 2 = 1 ( m o d   p ) b*b^{p-2}=1(mod\ p) bbp2=1(mod p)

​ 那么我们就可以推出来 逆元为 b p − 2 b^{p-2} bp2方了 那么求逆元的情况我们就可以 变成快速幂的问题了 注意 只有当p为质数的时候才成立 不然不符合费马小引理

​ 如果b和p不互质 那么就不存在逆元

接下来我们可以举一个简单的例子说明一下逆元 比如 我们的 b是4 p是3 我们给定一个b|a的数也就是a等于8 我们要把8/4 mod p等价成一个乘法 我们就可以去求 b p − 2 b^{p-2} bp2 也就是 4 然后这个4就是我们要求的逆元 我们会发现 4*8 mod 3 余2 和除法的结果相同 也就是说 这个4就是我们要求的逆元

​ coding如下:

#include<iostream>
using namespace std;
int n;
typedef long long int LL;
LL qmi(int a,int b,int p)
{
    // 求解 a^b%p的结果
    LL res=1;
    int k=b;
    while(k!=0)
    {
        // 如果k这个数二进制表示最后一位是1 也就是这一位
        if(k&1)
        {
            res=res*a%p;

        }
        // 左移一位看看下一位是不是1
        k=k>>1;
        a=a*(LL)a%p;


    }
    // cout<<"balabala"<<a<<endl;
    return res;


}
int main()
{
    cin>>n;
    while(n--)
    {
        int a,p;
        cin>>a>>p;
        if(a%p==0)
        {
            cout<<"impossible"<<endl;
            continue;
            
        }
        cout<<qmi(a,p-2,p)<<endl;



    }


    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值