快速幂取模(a^b%p问题)

快速幂取模功能

解决指数型取模类问题,防止进行连续的幂运算时造成int或long long范围越界的情况。应用快速幂取模算法,可以极大的优化算法的时间和空间。

底层原理

两数之积取模等于对两数分别取模然后对积取模。
即:
(a * b) % p = (a % p) * (b % p) % p

例题剖析

题目描述

给你三个整数 a,b,p,求 ab mod p。

输入格式

输入只有一行三个整数,分别代表 a,b,p。

输出格式

输出一行一个字符串 a^b mod p = s,其中 a,b,p 分别为题目给定的值, s 为运算结果。

输入输出样例

输入#1

2 10 9

输出#1

2^10 mod 9=7

提示

样例解释
2 10 = 1024,1024mod 9 = 7。
数据规模与约定
对于100% 的数据,保证0≤a,b<2 31 ,a+b>0,2≤p<2 31

思路方法:

没有接触过算法的小白可能就会这么做,将ab算出来,最后再对p取模。对于一些比较小的数据,用int或者long long存取是没有问题的,然而当数据大到一定程度时,用int或者long long存取就会造成数据超出范围

那么该如何解决这个问题呢?🙃

问题根源:
ab数据过大,超出范围。
因此,我们可以通过不断缩小a,b的规模来达到优化的效果。

根据上方的底层原理,我们不难想到这样一种解法:

#include<bits/stdc++.h>
using namespace std;
int main(){
    long long a,b,p;
    cin>>a>>b>>p;
    if(a == 0) return 0;
    if(b == 0) return 1;
    long long t = a,x = b;
    while(x - 1){//计算a的b次方,每一次中间结果都对p取模。
    	t *= a;
    	t %= p;
    	x--;
	}
    cout<<a<<"^"<<b<<" mod "<<p<<"="<<t;
    return 0;
}

对于一般的题目,其实这种优化已经达到需求了。但是这还会出现一个问题:
Time Limit Exceeded
问题根源:
上面的做法,仅仅对a的规模以及中间结果进行了优化,b的规模没有改变。
那么该如降低b的规模呢?🤔
例如:
78 = (7 * 7)4,这是b的规模就减半了,如果b为奇数,那么可以把中间值先乘上一个a,b的值就会-1,此时b变为偶数,然后重复上述过程。a的规模任按照上述的底层原理进行缩减规模。

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    long long a,b,p;
    cin>>a>>b>>p;
    long long ans = 1, x = a, y = b, z = p;
    a %= p; //缩小a的规模 
    while(b){//运算过程中不断对ans % p运算缩小规模,防止越界 
    	if(b % 2){//b为奇数时,提一个出来,让a与ans相乘 
    		ans = (ans * a) % p;
		}
		b /= 2;//b的规模减半 
		a = (a * a) % p;//同时a进行平方 
	}
    cout<<x<<"^"<<y<<" mod "<<z<<"="<<ans;
    return 0;
}
  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WTY2002

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值