快速幂取模算法的引入是从大数的小数取模的朴素算法的局限性所提出的,在朴素的方法中我们计算一个数比如5^1003%31是非常消耗我们的计算资源的,在整个计算过程中最麻烦的就是我们的5^1003这个过程
缺点1:在我们在之后计算指数的过程中,计算的数字不都拿得增大,非常的占用我们的计算资源(主要是时间,还有空间)
缺点2:我们计算的中间过程数字大的恐怖,我们现有的计算机是没有办法记录这么长的数据的,所以说我们必须要想一个更加高效的方法来解决这个问题
当我们计算AB%C的时候,最便捷的方法就是调用Math函数中的pow方法,但是有时A的B次方数字过大,即使是双精度的double也会溢出,这个时候为了得到AB%C的结果,我们会选择使用快速幂取模算法,简单快速的得到我们想要的结果。
为了防止数字溢出并且降低复杂度,我们需要用到下面的公式:
ab mod c = (a mod c)b mod c
这个公式的意思就是:积的取余等于取余的积的取余。很容易看出来这个公式是具有传递性的,这样我们可以通过不断的取余让a越来越小,防止出现溢出的情况。
理论上,有了这个公式我们就可以写代码了,通过不断的对a进行取模保证结果不会溢出,这确实能计算出较大次方的幂的模,但是这种方法的复杂度仍旧是O(N),并不快速。
为了更快速的计算出幂的模,我们还要依赖下面这个公式:
ab mod c = (a2)b/2 mod c , b为偶数
ab mod c = ((a2)b/2·a) mod c , b为奇数
这个公式很简单,原理就是不断的用a的平方来代替b,将b替换为原来的一半。因为我们通过第一个公式知道了一个数的模的相同次方的模相同(这句话说的有点绕,就是公式一的意思)。那么我们用a*a%c的结果来代替a效果是一样的。
所以根据上述的公式,我们得到复杂度O(logN)这样的计算快速幂的方法:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int a = in.nextInt(), b = in.nextInt(), c = in.nextInt();
int res = 1;
a %= c;
for (; b != 0; b /= 2) {
if (b % 2 == 1)
res = (res * a) % c;
a = (a * a) % c;
}
System.out.println(res);
}
}
这个算法大概如此,第一步先a%=c是为了将a缩小一些,防止在for中第一次进行a*a的时候数字溢出。在for循环中,如果是b为奇数则令res=res*a,直接先将a乘到结果中去,最后做处理,又是为了防止数字溢出直接将res*a的结果mod c操作。这个for循环中,早晚有一天b会等于1,进入if分支,最后将res的值计算完毕mod c退出for循环,的到最后的结果。
原神祈愿模拟器最新版
原神祈愿模拟器手机版是一款完整汉化的趣味原神抽卡模拟小游戏,
宝宝森林美食完整版
宝宝森林美食游戏最新版是一款十分有趣的休闲益智游戏,帮助宝宝
g沙盒仇恨官方英文版(gorebox)
G沙盒仇恨英文原版是一款最近非常火热的沙盒模拟类游戏,在这里
迷你世界测试服最新版2024
迷你世界测试服2021最新版,即迷你世界的先遣服版本,用户能
闪耀暖暖最新版2024
闪耀暖暖手游这是非常好玩的换装手游,游戏内容丰富有趣,游戏环