快速幂,快速幂取模

看了许多关于快速幂及快速幂取模的博客,今天分享一下自己对快速幂的理解,如果哪里写的不对,请在评论区留言,我会及时更改,谢谢。

先来看个题目

撞杆子的CC学姐
17级学姐中有个学姐,人称撞杆子的CC,因为CC学姐走路的时候总是在低头玩手机,所以经常撞杆子,在一次把鼻子撞破后,CC学姐在想自己出一次门究竟要撞多少个杆子。一天CC学姐打算去广场玩,已知CC学姐走完全程共撞n次杆子,CC学姐第一次撞杆子时是走了1米的时候,每次撞完杆子后潜意识都会改变自己的小心程度,即第i次撞杆子后经过2i % 107米后会撞下一个杆子,现在CC学姐想知道自己走了多远。

输入格式

输入一个n(1 <= n <= 10^5),CC学姐走完全程要撞的杆子数量

输出格式

输出一个s,CC学姐走完全程所走的距离

样例输入

1
3
4

样例输出

1
7
15

分析:这个题首先想到的就是暴力求解,然后手写个pow函数,然后跑一次循环。

int pow(int a,int b)
{
    int ans=1;
    int i;
    for(i=1;i<=b;i++)
        ans*=a;
    return ans;
}

时间复杂度为O(n),很显然时间复杂度比较高,我们可以使用快速幂算法将其降到O(logn)。

快速幂

博主是采用位运算来解释,因为位运算比较好理解而且速度比较快。

举个例子:
23
对于指数3我们可以化成二进制的形式,也就是0011;
然后把二进制化成权值的表示形式 0* 23+0* 22+1* 21+1* 20;

换到原来的式子中变成
2^ ( 1* 2 1+1* 20)
即 2^ (1*21) * 2^ (1 * 20)

也就是说我们可以根据二进制的权值来进行计算。对于位的部分我们依次取,取到是0便累乘,是1就把累乘的答案乘到答案中,所以可以得到如下代码:

int quick(int x,int n)//x为底数,n为指数
{
    int sum=1;//最小2^0是1
    while(n)
    {
        if(n&1)
        {
            sum*=x;
        }
        x*=x;
        n>>=1;
    }
    return sum;
}

解释一下这里的n&1。
1化成二进制后只有最后一位是1,其余的都是0,与n进行异或便可得到n最后一位的值。例如上面的23和1异或得到
0011 & 0001
然后n每次右移一位,便可取出n的所有位。

快速幂取模

懂了上面的快速幂之后,理解快速幂取模也就容易很多。

先来看一下数论里面的一个定理:
(a*b)%c=((a%c) *(b%c))%c;
由这个式子可推出另外一个定理:
(a^ b)%c=(a%c) ^b%c;

快速幂取模主要应用的是第二条推理,我们可以不断的对底数进行取模,缩小底数范围,然后再对整个快速幂进行取模,就可以得到快速幂取模的操作,具体代码如下。

int quick(int x,int n,int m)//x为底数,n为指数,m为模
{
    int sum=1;
    while(n)
    {
        if(n&1)
        {
            sum=(sum*x)%m;
        }
        x=(x*x)%m;
        n>>=1;
    }
    return sum;
}

以上是快速幂和快速幂取模的核心代码,对于给出的例题完整代码如下

#include<stdio.h>
int quick(int x,int n,int m)
{
    int sum=1;
    while(n)
    {
        if(n&1)
        {
            sum=(sum*x)%m;
        }
        x=(x*x)%m;
        n>>=1;
    }
    return sum;
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        int i;
        long long int  sum=0;
        for(i=0;i<n;i++)
        {
            sum+=quick(2,i,107);
        }
        printf("%lld\n",sum);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值