快速幂取模:就是求a^bMODc (这就是著名的RSA公钥的加密方法)
因为当AB很大的时候直接求这个问题会在时间和空间上消耗很大
对此类问题我们可以采用以下几种做法:
在这里我随便利用一个例子:HDOJ 的 1420题:
点击打开链接
算法1:
利用公式a*b%c=((a%c)*b)%c(在这里a=b),这样每一步都进行这种处理,这就解决了a^b可能太大存不下的问题,
但这个算法的时间复杂度(O(n))依然没有得到优化,再有些题目可能会超时。
代码如下:
public class P1420{
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
while(n-->0){
long a=sc.nextLong();
long b=sc.nextLong();
long c=sc.nextLong();
long ans=1; //记录结果
if(a>c){
a=a%c;
}
for(int i=1;i<=b;i++){
ans=ans*a%c;
}
System.out.println(ans);
}
}
}
算法2:就是利用2分的思想,通过使时间降低为O(log(n))
具体思路为:
我们可以把b的二进制转换为:
b = p(n)*2^n + p(n-1)*2^(n-1) +…+ p(1)*2 + p(0) 的形式 其中p(n)等于0或者1
则a^b = a^ (p(n)*2^n + p(n-1)*2^(n-1) +...+ p(1)*2 + p(0))
=
a^(p(n)*2^n) * a^(p(n-1)*2^(n-1)) *...* a^(p(1)*2) * a^p(0) ———(*)
这里p(n)=0的情况我们不用考虑:因为p(n)=0时 a^p(n)=1;任何数乘以1都等于它本身
化简多项式(*)可以根据秦九韶算法:
点击打开链接
可以得到:
a^(2^i) = a^(2^(i-1) * 2) = ( a^( p(i) * 2^(i-1) ) )^2
所以我们可以结合前面的得到:a^(2^i)%c = ( (a^(2^(i-1))%c) * a^(2^(i-1))) %c
代码如下:
package acm;
import java.util.Scanner;
public class P1420 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
while(n-->0){
long a=sc.nextLong();
long b=sc.nextLong();
long c=sc.nextLong();
long ans=1;//记录结果
if(a>c){
a=a%c; //如果a>c,就先把a对c取余
}
while(b!=0){
if((b&1)!=0){
//位运算,若(b&1)=0则说明不用加入计算
ans=(ans*a)%c;
}
b=b/2;//使b的二进制向左移动一位或者可以使用b=b>>1;
//b=b>>1;
a=(a*a)%c;
}
System.out.println(ans);
}
}
}