快速幂

本文详细介绍了同余定理及其性质,并基于此讲解了快速幂算法的原理及其实现方式,帮助读者理解如何高效地计算大数的幂次模。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

##基于同余定理的快速幂 ##
再讲快速幂之前我们先来说一下同余定理这个神奇的东西哈:

同余定理:

  1. 所谓同余,字面上的意思就是两个数或者多个数的除以一个数,所得的余数相同
    如果说a和b同时除以c,所得的余数均为r,那么可以写成a = mc + r ,b = nc + r(m和n为任意整数),那么我们就可以用数学公式写成 a ≡ b (mod c),即 a 和 b 同余。比如 9 和 2 除以 7 的余数均为2,那么我们可以写成 9 ≡ 2 (mod 7)。
  2. 网上还有一种定义,即如果两个数 a 和 b 之差能被 c 整除,那么我们就说 a 和 b 对模数 c 同余(关于 c 同余)。比如,9 - 2除以 7 正好除尽,我们就说 9 和 2 对于模数 7 同余。它的另一层含义就是说,a = mc + r ,b = nc + r,( a - b ) = ( m - n )c对c能除尽,那么 a 和 b 同余。反之,令a = mc + r1 ,b = nc + r2 若c | a - b ,则c | c ( m - n ) + r1 - r2 ,则 c | r1 - r2,但| r1 - r2 | = 0,故r1 = r2,即 a ≡ b ( mod c)。
    推论: a ≡ b (mod c)的充要条件是a = c t +b(t为整数,可能改成a - b = ct 好看一点)。

定理1: 同余关系具有自反性、对称性、传递性,即

1) a ≡ a ( mod m) ;

2)若 a ≡ b (mod m), 则b ≡ a (mod m);

3)若a ≡ b (mod m) 且 b ≡ c (mod m),则a ≡ c ( mod m) .


定理2:若 a ≡ b ( mod m) , c ≡ d (mod m),则
对于两个的同模同余式也能够进行加减乘运算。

1)a + c ≡ b + d (mod m);

2)a - c ≡ b - d (mod m);

3)ac ≡ bd (mod m).

第一第二个推论还挺好理解的,现在来证一下第三个推论:
设 a = wm + p ; b = xm + p ; c = ym + q ; d = zm +q ;
ac = ( wy )m^2+( wq +yp)m +pq
bd= ( xz ) m^2 +(xq + zp)m +pq
所以 ac ≡ bd( mod m )
对于乘法还有下面的推论:
推论 : 若 a ≡ b ( mod m ),n 为自然数,则 an ≡ bn ( mod m )。
有的题要叫你“输出答案mod xxxxx的结果”,这是为了避免高精度运算,因为这里的结论告诉我们在运算过程中边算边mod和算完后再mod的结果一样。


定理3: 若 ca ≡ cb ( mod m) , ( c , m ) = d, 且 a , b 为整数,则 a ≡ b ( mod m/d).

推论:若 ca ≡ cb (mod m) , ( c , m ) = 1 , 且 a , b 为整数,则 a ≡ b ( mod m ).


定理4 :若 a ≡ b ( mod m ), a ≡ b ( mod n ),则 a ≡ b ( mod [m,n] ).

推论:若 a ≡ b ( mod mi ), i = 1,2,…,n,则 a ≡ b ( mod [m1,m2,…,mn] ).

同余定理需要注意的一点是:主要是对余数的研究

下面我们进入各位期待的快速幂:
首先我们先了解两个公式(蒙哥马利幂模运算公式,由上面的同余定理推导出):
1)a * b % n =(a % n ) * ( b % n ) % n
2)(a + b)% n =(a % n + b % n ) % n

一般这种题通常会让我们求 a ^ b % c ,即 a 的 b 次幂对 c 取模 , 我们假设 a = 5 , b = 6 , c = 3
则 a 的 b 次方对 c 取模的值为5 ^ 6 % 3 ,转化为(5 ^ 2)^ 3 % 3 ,转化为(5 ^ 2)((5 ^ 2)^2) % 3,即((5 ^ 2)%3)((5 ^ 2)^2 % 3)% 3
依据同余定理可得下列公式:
如 a ^ 5,可转化为((a ^ 2)^2)
a % c

以下是代码实现:

#include<iostream>
using namespace std;
long long remn(long long a,long long b,long long c)
{
	long long ans = 1;  
        a %= c;  						//先让a % = c是为了防止 a 很大,c很小的情况,毕竟a ≡a % c(mod c),这样做不会使(a*a)超限 
        while(b > 0){  
            if(b & 1){  				//(b&1)位运算判断奇偶,b&1=1是奇数,按位与运算
                ans = (ans * a) % c;  	//是奇数,可与之前是奇数是所求得的结果相乘求余,此时ans保存的是(之前ans乘上(a的平方次幂对c取模) )再对c取模的值 
            }  
            b >>= 1;					//为运算,右移一位等于除以2,最后必然得到一个奇数1,可由上方if语句求得结果
            a = (a * a) % c;  			//若是偶数,可相乘求余,此时a保存的是之前a的平方次幂对c取模 
        }  
       	cout<<ans<<endl;
}
int main()
{
	long long  x,y,z;
	while(cin>>x>>y>>z){
		remn(x,y,z);
	}
	return 0;
}

我建议读者多测试几组数据,并用编译器调试一下,看看每一步,每个变量的值是如何变化的,这样有助于理解,我就是通过调试理解的,嘻嘻,错误的地方还望各位大佬指正,谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值