快速幂(三)|快速幂取模

62 阅读2分钟

上一篇🔗快速幂(二)|矩阵快速幂求解fibonacci

本文阅读时间约5分钟,你将获得:

通俗易懂的快速幂取模讲解,不懂不要小钱钱的那种~

本文是快速幂算法的应用的第二篇,其他快速幂应用还包括:

  • 高精快速幂

简介

在实际问题中,题目常常会要求对一个大素数取模,这是因为计算结果可能会非常巨大,但是在这里考察高精度又没有必要。这时我们的快速幂也应当进行取模,此时应当注意,原则是步步取模,如果MOD较大,还应当开long long。

模运算规则

  • 模运算

    • (a+b)modp=((amodp)+(bmodp))modp(a + b) \mod p = ((a \mod p) + (b \mod p)) \mod p
    • (ab)modp=((amodp)(bmodp))modp(a - b) \mod p = ((a \mod p )- (b \mod p) ) \mod p
    • (a×b)modp=((amodp)×(bmodp))modp(a \times b)\mod p = ((a \mod p )\times( b \mod p)) \mod p
    • abmodp=((amodp)b)modpa ^ b \mod p = ((a \mod p)^b) \mod p

我们主要用到的是第三个

(a×b)modp=((amodp)×(bmodp))modp(a \times b)\mod p = ((a \mod p )\times( b \mod p)) \mod p

(a * b) % p = (a % p * b % p) % p

也就是:积的取余==取余的积的取余

这样,nn次幂可以拆分成一个平方计算后就剩余n/2n/2的次幂了

递归做法

c=10000007 
# 值10000007是一个质数,这使它成为模数的一个好选择,
# 因为它减少了碰撞的可能性并确保结果均匀分布。

def divide(a, b):
    """
    This function calculates a^b%c using recursion.
    :param a: The base number.
    :param b: The exponent.
    :return: The result of a^b%c.
    """
    # 如果b等于0,返回1
    if b == 0:
        return 1
    # 如果b是偶数,
    # 递归调用divide((a % c) * (a % c), b // 2)
    # 并返回结果对c取模的值
    elif b % 2 == 0:
        return divide((a % c) * (a % c), b // 2) % c
    # 如果b是奇数,返回a对c取模的值乘以
    # divide((a % c) * (a % c), (b - 1) // 2)对c取模的值
    else:
        return a % c * divide((a % c) * (a % c), (b - 1) // 2) % c

非递归做法

c = 1000000007 # 定义模数

def divide(a, b):
    """
    This function calculates a^b%c using recursion.
    :param a: The base number.
    :param b: The exponent.
    :return: The result of a^b%c.
    """
    a %= c
    # 初始化结果为1
    res = 1
    # 当b不等于0时,进行循环
    while b != 0:
        # 如果b是奇数,将res乘以a对c取模的值并对c取模
        if b % 2 == 1:
            res = (res * a) % c
        # 将a平方并对c取模
        a = (a * a) % c
        # 将b除以2
        b //= 2
    # 返回结果
    return res

参考资料

一文彻底搞懂快速幂(原理实现、矩阵快速幂) - bigsai - 博客园 (cnblogs.com)

【竞赛向】斐波那契数列的矩阵快速幂求法_哔哩哔哩_bilibili