高速幂取余算法

以下是一个高速幂的介绍:

先贴一个秦九韶算法(Horner算法)的原理:

设有项的次函数

将前项提取公因子,得

再将括号内的前项提取公因子。得

如此重复提取公因子,最后将函数化为

......

即为所求

以下是解说高速幂的:(By  夜せ︱深   感谢作者)

高速幂取模算法

在站点上一直没有找到有关于高速幂算法的一个具体的描写叙述和解释,这里,我给出高速幂算法的完整解释,用的是C语言。不同语言的读者仅仅好换个位啦,毕竟读C的人较多~

所谓的高速幂。实际上是高速幂取模的缩写,简单的说,就是高速的求一个幂式的模(余)。在程序设计过程中。常常要去求一些大数对于某个数的余数。为了得到更快、计算范围更大的算法,产生了高速幂取模算法。

[有读者反映在讲高速幂部分时有点含糊,所以在这里对本文进行了改动,作了更具体的补充。争取让很多其它的读者一目了然]

我们先从简单的样例入手:求a^b % c = ?

算法1.首先直接地来设计这个算法:

int ans = 1;

for(int i = 1;i<=b;i++)

{

ans = ans * a;

}

ans = ans % c;

这个算法的时间复杂度体如今for循环中,为O(b).这个算法存在着明显的问题。假设a和b过大,非常easy就会溢出。

那么,我们先来看看第一个改进方案:在讲这个方法之前,要先有这样一个公式:a^b%c=(a%c)^b%c.这个公式大家在离散数学或者数论其中应该学过。只是这里为了方便大家的阅读,还是给出证明:

引理1:a^b%c = (a%c)^b%c

上面公式为以下公式的引理,即积的取余等于取余的积的取余。

证明了以上的公式以后,我们能够先让a关于c取余,这样能够大大降低a的大小,

于是不用思考的进行了改进:

算法2:

int ans = 1;

a = a % c; //加上这一句

for(int i = 1;i<=b;i++)

{

ans = ans * a;

}

ans = ans % c;

聪明的读者应该能够想到,既然某个因子取余之后相乘再取余保持余数不变,那么新算得的ans也能够进行取余,所以得到比較良好的改进版本号。

算法3:

int ans = 1;

a = a % c; //加上这一句

for(int i = 1;i<=b;i++)

{

ans = (ans * a) % c;//这里再取了一次余

}

ans = ans % c;

这个算法在时间复杂度上没有改进,仍为O(b),只是已经好非常多的。可是在c过大的条件下,还是非常有可能超时,所以。我们推出下面的高速幂算法。

高速幂算法依赖于下面明显的公式,我就不证明了。

那么我们能够得到下面算法:

算法4:

int ans = 1;

a = a % c;

if(b%2==1)

ans = (ans * a) mod c; //假设是奇数,要多求一步,能够提前算到ans中

k = (a*a) % c; //我们取a2而不是a

for(int i = 1;i<=b/2;i++)

{

ans = (ans * k) % c;

}

ans = ans % c;

我们能够看到,我们把时间复杂度变成了O(b/2).当然,这样子治标不治本。

但我们能够看到,当我们令k = (a * a) mod c时,状态已经发生了变化,我们所要求的终于结果即为(k)b/2 mod c而不是原来的ab mod c,所以我们发现这个过程是能够迭代下去的。

当然,对于奇数的情形会多出一项a mod c,所以为了完毕迭代,当b是奇数时,我们通过

ans = (ans * a) % c;来弥补多出来的这一项。此时剩余的部分就能够进行迭代了。

形如上式的迭代下去后。当b=0时,全部的因子都已经相乘。算法结束。于是便能够在O(log b)的时间内完毕了。于是。有了终于的算法:高速幂算法。

算法5:高速幂算法

int ans = 1;

a = a % c;

while(b>0)

{

if(b % 2 == 1)

ans = (ans * a) % c;

b = b/2;

a = (a * a) % c;

}

将上述的代码结构化。也就是写成函数:

int PowerMod(int a, int b, int c)

{

int ans = 1;

a = a % c;

while(b>0)

{

if(b % 2 = = 1)

ans = (ans * a) % c;

b = b/2;

a = (a * a) % c;

}

return ans;

}

本算法的时间复杂度为O(logb),能在差点儿全部的程序设计(竞赛)过程中通过,是眼下最经常使用的算法之中的一个。

下面内容仅供參考:

扩展:有关于高速幂的算法的推导,还能够从还有一个角度来想。

=? 求解这个问题,我们也能够从进制转换来考虑:

将10进制的b转化成2进制的表达式:

注意此处的要么为0。要么为1,假设某一项,那么这一项就是1,这个相应了上面算法过程中b是偶数的情况,为1相应了b是奇数的情况[不要搞反了。读者自己好好分析,能够联系10进制转2进制的方法],我们从依次乘到。对于每一项的计算,计算后一项的结果时用前一项的结果的平方取余。对于要求的结果而言,为时ans不用把它乘起来,[由于这一项值为1],为1项时要乘以此项再取余。这个算法和上面的算法在本质上是一样的。读者能够自行分析,这里我说不多说了,希望本文有助于读者掌握高速幂算法的知识点。当然。要真正的掌握,不多练习是不行的。

时间: 2024-10-11 12:34:28

高速幂取余算法的相关文章

快速幂取余算法

下面是一个快速幂的介绍: 先贴一个秦九韶算法(Horner算法)的原理: 设有项的次函数 将前项提取公因子,得 再将括号内的前项提取公因子,得 如此反复提取公因子,最后将函数化为 令 ...... 则即为所求 下面是讲解快速幂的:(By  夜せ︱深   感谢作者) 快速幂取模算法 在网站上一直没有找到有关于快速幂算法的一个详细的描述和解释,这里,我给出快速幂算法的完整解释,用的是C语言,不同语言的读者只好换个位啦,毕竟读C的人较多~ 所谓的快速幂,实际上是快速幂取模的缩写,简单的说,就是快速的求

快速幂取余 [转]

转自: http://blog.csdn.net/acm_code/article/details/38270829 求a^b mod c 算法1. 首先直接地来设计这个算法: int ans=1, i; for(i=1;i<=b;i++) ans*=a; ans%=c; 这个算法的时间复杂度体现在for循环中,为O(b). 这个算法存在着明显的问题,如果a和b过大,很容易就会溢出. 那么,我们先来看看第一个改进方案:在讲这个方案之前,要先有这样一个公式: a^b mod c=(a mod c)

【转】C语言快速幂取模算法小结

(转自:http://www.jb51.net/article/54947.htm) 本文实例汇总了C语言实现的快速幂取模算法,是比较常见的算法.分享给大家供大家参考之用.具体如下: 首先,所谓的快速幂,实际上是快速幂取模的缩写,简单的说,就是快速的求一个幂式的模(余).在程序设计过程中,经常要去求一些大数对于某个数的余数,为了得到更快.计算范围更大的算法,产生了快速幂取模算法.我们先从简单的例子入手:求abmodc 算法1.直接设计这个算法: int ans = 1; for(int i =

HDU1061_Rightmost Digit【快速幂取余】

Rightmost Digit Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 33161    Accepted Submission(s): 12696 Problem Description Given a positive integer N, you should output the most right digit of

CSU - 1556 Jerry&amp;#39;s trouble(高速幂取模)

[题目链接]:click here [题目大意]:计算x1^m+x2^m+..xn^m(1<=x1<=n)( 1 <= n < 1 000 000, 1 <= m < 1000) [解题思路]:高速幂取模 代码: solution one: #include<bits/stdc++.h> #define LL long long using namespace std; const LL mod=(LL)1e9+7; LL pow_mod(LL a,LL p

poj 1845 Sumdiv (同余定理,快速幂取余)

链接:poj 1845 题意:求A^B的所有因子的和对9901取余后的值 如:2^3=8,8的因子有 1,2,4,8,所有和为15,取余后也是15 应用定理主要有三个: (1)整数的唯一分解定理: 任意正整数都有且只有一种方式写出其素因子的乘积表达式. A=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^kn)   其中pi均为素数 (2)约数和公式: 对于已经分解的整数A=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^kn) 有A的所有因子之和为 S = 

hdu 2817 A sequence of numbers(快速幂取余)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2817 题目大意:给出三个数,来判断是等差还是等比数列,再输入一个n,来计算第n个数的值. 1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #define m 200907 5 6 using namespace std; 7 8 __int64 fun(__int64 j,__int64 k) 9

LightOJ - 1282 - Leading and Trailing(数学技巧,快速幂取余)

链接: https://vjudge.net/problem/LightOJ-1282 题意: You are given two integers: n and k, your task is to find the most significant three digits, and least significant three digits of nk. 思路: 后三位快速幂取余,考虑前三位. \(n^k\)可以表示为\(a*10^m\)即使用科学计数法. 对两边取对数得到\(k*log

Raising Modulo Numbers_快速幂取模算法

Description People are different. Some secretly read magazines full of interesting girls' pictures, others create an A-bomb in their cellar, others like using Windows, and some like difficult mathematical games. Latest marketing research shows, that