算法竞赛小白进阶之路---快速幂思想&&倍增&&64位整数乘法的题目

53 阅读4分钟

这个文章的主要内容:倍增思想,快速幂算法题目;

其实这个主要是和高精度有点联系,算是这个高精度的进阶的题目,因此在学习这个高精度的时候老师说让啃一下这种比较难的题目,所以才有了现在的这个情况;

1.快速幂

这个在我们的后面需要学习的数学章节会经常使用到,因此这个快速幂的方法还是非常的实用的;

为什么叫做快速幂,这个很容易理解,因为这类题目涉及到的就是幂运算,为什么叫做快速呢,因为这个里面我们使用了倍增的思想,因此这个比正常的方法都是快的;

image-20250717204552497

下面的这个是快速幂的代码:

1)和我们的高精度相比,这个代码真的是非常短了,主要还是理解这个倍增的过程把;

2)首先还是从这个main函数入手,输入三个数据,两个乘数,一个是取模运算的数据,按照这个指定的格式进行输出,因此这个就是使用的printf进行指定的格式的输出的;

3)调用这个函数的时候,这个就是我们的快速幂的核心了;

实际上我们的这个快速幂是对于这个指数,也就是我们的a的b次方运算里面的这个b进行二进制表示,二进制里面只有这个0,1,01之类的,是1的时候,我们就需要进行这个

#include <iostream>

using namespace std;

typedef long long LL;

LL a, b, p;

// 快速幂的模板
LL qpow(LL a, LL b, LL p)
{
    LL ret = 1;
    while(b)
    {
        if(b & 1) ret = ret * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return ret;
}

int main()
{
    cin >> a >> b >> p;

    printf("%lld^%lld mod %lld=%lld",a, b, p, qpow(a, b, p));

    return 0;
}

4)下面的这个是老师上课时候的这个板书的具体的内容:使用的是11进行举例的,也就是把这个11进行二进制表示之后就是1011,这个也就表示成为我们的a的8次方乘以平方,乘以1次方;

这个8,2,1具体是如何得到的呢,就是我们的二进制得到的,也就是2的对应下标次方即可得到;

image-20250717205035479

5)把这个思路应用到我们的代码里面去,那就是下面的这个函数:

ret存放的是我们的这个结果,b>>=1这个就是每一次都需要对于我们的b进行右移的操作,比如上面的这个1011的二进制表示,我们每一次右移,就可以达到对于这个二进制里面的每一位进行处理的这个效果;

6)b&1就是确定这个当前处理这个位是不是1,如果是1的话,这个时候就是真,进入我们的判断语句的内容,ret*a也就是每一次进行这个乘的过程,多少次呢,就取决于我们的这个b的大小,因为这个是while循环;

a=a*a就是我们的倍增的过程,从a的平方,到4次方,到8次方,到16次方这样倍增的过程

7)最后就是这个%p的操作,这个是我们的取模运算的特性,当这个式子里面只有这个取模运算和这个乘法运算的时候,我们的这个取模运算放在任何的这个地方都是没有问题的,因此这个地方为了解决这个存不下的问题,多次使用了这个取模的运算;

image-20250717205219568

2.64位整数乘法

这个实际上就是食欲这个高精度乘法的这个范畴,但是这个里面使用了我们的倍增的思想,所以放到了这个位置

下面的这个是题目:

image-20250717205745916

下面的这个是代码:

1)都是这个倍增的思想,这个快速幂运算的那个函数是完全一样的思想,不同的地方就是上面的是快速的乘法,下面的这个是快速的加法,其他的没有任何的区别,大家可以仔细的比对一下,这个思路也是完全一致的;

2)主函数里面也就那么一点东西,因此这个我就不在进行这个赘述了;

#include <iostream>

using namespace std;

typedef long long LL;

LL a, b, p;

// 快速乘的模板
LL qmul(LL a, LL b, LL p)
{
    LL sum = 0;
    while(b)
    {
        if(b & 1) sum = (sum + a) % p;
        a = (a + a) % p; // 倍增
        b >>= 1;
    }
    return sum;
}

int main()
{
    cin >> a >> b >> p;

    cout << qmul(a, b, p) << endl;

    return 0;
}