洛谷P1226 【模板】快速幂||取余运算

题目描述:

输入b,p,k的值,求bp mod k的值。其中b,p,k*k为长整型数

 

题解:

我们要让计算机很快地求出a^b

暴力相乘的话,电脑要计算 b次。用快速幂,计算次数在 log(b) 级别,很实用。

怎么实现呢?

我们知:

(1)如果将 a 自乘一次,就会变成 a2 。再把 a2 自乘一次就会变成 a4 。然后是 a8……以此类推。

(2)axay = a(x+y)



过程会是这样:

·假设我们拿到了 aa,并且 b = 11。想求 a11,但是又不想乘11次,有点慢。

·稍稍观察一下 b = 11,二进制下是 b = 1011

·制作一个 base。现在 base = a,表示的是,a1 = a

·制作一个 ans,初值 1,准备用来做答案。


while(b > 0)
{
if(b & 1)
    ans *= base;

/*关于 b & 1:
x & y 是二进制 x 和 y 的每一位分别进行“与运算”的结果。
与运算,即两者都为 1 时才会返回 1,否则返回 0。
那么 b & 1

          二进制
b     =    1011
1     =    0001
b&1   =    0001

因为 1(二进制)的前面几位全部都是 0,
所以只有 b 二进制最后一位是 1 时,b & 1 才会返回 1。)*/

·然后 base通过自乘一次,使自己变成 a2

base *= base;

同时

b >>= 1;
}

接着再按照以上顺序循环,以此类推。



但有时候快速幂乘的过程中会爆掉,所以我们用到快速加

原理相同,只是变一下符号。

附上代码:

#include<stdio.h>
long long b,p,k;
long long ksj(long long x,long long y)
{
    long long cnt=0;
    while(y)
    {
        if(y%2)
            cnt=(cnt+x)%k;
        x=(x+x)%k;
        y/=2;
    }
    return cnt;
}
long long ksm(long long x,long long y)
{
    long long cnt=1;
    while(y)
    {
        if(y%2)
            cnt=ksj(cnt,x)%k;
        x=ksj(x,x)%k;
        y/=2;
    }
    return cnt;
}
int main()
{
    scanf("%lld%lld%lld",&b,&p,&k);
    long long ans=ksm(b,p);
    if(p!=0)
        printf("%lld^%lld mod %lld=%lld",b,p,k,ans);
    else
        printf("%lld^%lld mod %lld=0",b,p,k);        
}

 

posted @ 2018-10-19 22:32  jiangminghong  阅读(173)  评论(0编辑  收藏  举报