定理:要计算只包含加减乘的整数表达式除以整数m的余数时,可以在每步计算时对m取余
对于:a*a %n= (a%n) *(a%n) %n
解决 a*a %n 或 a**k %n 中 数据太大超出范围的问题
乘法求模数
对于
a*a%n
可以
#如果n*n的计算不超出数的范围
def multi(a,b,n):
ans = 0;
ans=a%n
ans=ans*(b%n)%n
return ans
}
#如果超出范围
def multi(a,b,n):
ans =0;
while(b!=0):
if(b%2==1) #b为奇数 a*b=a*(b-1)+a
ans+=a
ans=ans%n #b-1为偶数
#a*b=(a*2%n) * b//2
a*=2;
a%n
b=b//2;
return ans
乘方取模数
a**k%n
1.一般
由于
a**k%n
=a%n* a**(k-1)%n %n
=a*(a%n)%n* a**(k-2)%n %n
代码
ans=1
for i in range(k):
ans=ans*a%n
但指数k一次减1太慢
2.优化
a**k%n
k为奇数 指数变换
a**k%n
=a%n* a**(k-1)%n %n
k为偶数
a**k%n 基数变换
=(a*a)**k/2 %n
奇数时指数k-1
偶数时基数a*a
n//2后不是奇数就是偶数
最后一次n=n//2 =0时 n一定为1
则最后一次执行操作一定会将结果保存到ans里
代码
def multimod(a,k,n):
ans=1
while(k!=0):
if k%2==1: #奇数
ans=ans*a%n
a=a*a%n
k=k//2 #整除2
return ans
快速幂取模
将上面结合起来
def multimod(a,k,n):
ans=1
while(k!=0):
if k%2: #奇数
ans=multi(ans,a,n)
a=multi(a,a,n)
k=k//2 #整除2
return ans