快速幂取模功能
解决指数型取模类问题,防止进行连续的幂运算时造成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;
}