温习(一)——快速幂

来源:互联网 发布:linux shutdown now 编辑:程序博客网 时间:2024/06/15 14:16

快速幂,是属于分治的一类习题,其思想如同分治,就是分而治之,所以看到题目的大数据,就要思考如何将大问题拆分成若干个相同解法的小问题,所以推导公式:

  • (a^b)%k=a^(b/2)*a^(b/2)*a(b%2)
    所以,这就是这道题目的一般性推导公式,这时程序就写出来了
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<math.h>long long b,p,k;long long work(int n){    if(n==0)return 1;    long long tmp=work(n/2)%k;    tmp=(tmp*tmp)%k;    if(n&1)tmp=(tmp*b)%k;    return tmp%k;}int main(){    scanf("%lld%lld%lld",&b,&p,&k);    printf("%lld^%lld mod %lld=",b,p,k);    b%=k;    printf("%d\n",work(p));    return 0;}

当然这并不是最快的快速幂,你还可以采用更高效的方法,如二进制:
在二进制中,有一个神奇的运算叫做按位与,它的意思是如果在对其的情况下,两位都是1,取出来的结果就是1,否则就是0。在这个的基础上,我们在推导n&1的情况(n为任意整数):
若n为11,则(n)10=(11)10=(1011)2 00001011
所以,11&1———————————–00000001
00000001
这个方法可以用来判断这个数的奇偶(这不是重点),但真正神奇的是下面这一个式子:
(a^11)%k=(a^8)%k*(a^2)%k*(a^1)%k
这也是分治的思想,运用二进制,使时间复杂度缩短为log2(a)。

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<math.h>long long b,p,k;int main(){    int i,j,n,m;    scanf("%lld%lld%lld",&b,&p,&k);     printf("%lld^%lld mod %lld=",b,p,k);    b%=k;    long long tmp=b,ans=1;    while(p!=0){        if(p&1){            ans=(ans*tmp)%k;        }        tmp=(tmp*tmp)%k;        p>>=1;    }    printf("%lld\n",ans%k);    return 0;}

这里有一道快速幂的题目:转圈游戏,这道题目是一道NOIP提高组的题目,总体来说就是要推导公式,这一题给大家思考,提供标程:

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<math.h>int work(int b,int n,int k){    if(n==0)return 1;    int tmp=work(b,n/2,k)%k;    tmp=(tmp*tmp)%k;    if(n&1)tmp=(tmp*b)%k;    return tmp%k;}int main(){    int i,j,k,n,m,x;    scanf("%d%d%d%d",&n,&m,&k,&x);    int b=10;b%=n;    int tmp=work(b,k,n);    tmp=(tmp*m)%n;    tmp+=x;tmp%=n;    printf("%d\n",tmp);    return 0;}//公式:(x+m*10^k)%n 

这里是改进版的(二进制实现):

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<math.h>int bb,pp;int main(){    int i,j,n,m,k,x;    scanf("%d%d%d%d",&n,&m,&k,&x);    bb=10;bb%=n;pp=k;    int ans=1;    while(pp!=0){        if(pp&1){            ans=(ans*bb)%n;        }        bb=(bb*bb)%n;        pp>>=1;    }    ans=(ans*m)%n;    ans+=x;ans%=n;    printf("%d\n",ans);    return 0;}//(x+m*10^k)%n
原创粉丝点击