ACWing 89 a^b mod p 快速幂运算

写题解旨在记录自己算法的学习过程

题目理解:

求a的b次方对p取模的结果

输入格式

三个整数 a,b,p,在同一行用空格隔开。

输出格式

输出一个整数,表示a^b mod p的值。

数据范围

0≤a,b ≤10^9
1≤p≤10^9


考点:

1.取模运算的性质:

[注]:模运算对于学算法的同学来说是需要记住的,虽然我这题的时候没记住hhhh

加法:(a + b) % p = (a % p + b % p ) % p                 (1)

减法:(a - b) % p = (a % p - b % p ) % p                   (2)

乘法:(a * b) % p = [(a % p) * (b % p)] % p               (3)

高阶次取模:(a ^ b)% p= ((a % p) ^ b) % p          (4)  

2.快速幂运算

错解:不能使用pow函数,因为pow的返回值为double类型,而且转成int后会出现精度损失,得不到正确的结果;

同理使用一层for循环会超时,因为时间复杂度为O(N)

long long int ex(int a, int b)
{
    long long int result = 1;
    
    for (int i = 1; i <= b; i++)
        result *= a;
        
    return result;
}


提示:以下是本篇文章正文内容,下面案例可供参考

一、快速幂计算方法

正确方法:使用位运算的方法

例如a =2 ,b=11;

2的11次方可以拆分为以下四项之积:

2^{_{11}} = 2^{1*2^{3}} * 2^{0*2^{2}} * 2^{1*2^{1}} * 2^{1*2^{0}} = 2^{8} * 2^{2} * 2^{1} =2^{11}

1*2^{3}、 0*2^{2}1*2^{1}1*2^{0}的系数分别为1、0、1、1

11的二进制数为1011,恰好和以上四个数对应

2^3、2^2、2^1、2^0,可以看成是计算1011各个位数的十进制数

那么我们就可以推出计算快速幂的方式:

①将指数转换为二进制数,例如将11转换为二进制数 1011

②判断每一位二进制数是否为1 ,为1的话就将其乘上a对应的次方

 

long long int quick_ex(int a, int n)
{
    long long int result = 1;   //用于存储项累乘与返回最终结果,由于要存储累乘所以要初始化为1
    while (n> 0)                //退出条件为n为0
    {
        if (n& 1){            //n的最后一位为1就累乘
           result *= a;         //累乘当前项并存储
            }          
                                //例如1001的当前计算位就是1, 100*1* 星号中的1就是当前计算使用的位
        
        a*= a;               //计算下一个项,例如当前是n^2的话计算下一项n^2的值
                               
        n>>= 1;            //指数位右移,确保每次n&1时都是和n的二进制数的最后一位进行比较
                                //一次的右移将舍弃一个位例如1011(2)一次左移后变成101(2)
    }
    return result;              //返回最终结果
}

本题的计算代码如下:
 

#include <iostream>

using namespace std;


long long ex(long long a, long long n, long long mod) {
    long long res = 1;
    while (n) {
        if (n & 1) {
            res = res * a % mod;
        }
        a = a * a % mod;
        n = n >> 1;
    }
    return res % mod;
}

int main() {
    long long a, n, mod;
    cin >> a >> n >> mod;
    cout << ex(a, n, mod);
    return 0;
}

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值