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