acm数论之旅(转载) -- 快速幂
0和1都不是素数,也不是合数。
a的b次方怎么求
pow(a, b)是数学头文件math.h里面有的函数
可是它返回值是double类型,数据有精度误差
那就自己写for循环咯
LL pow(LL a, LL b){//a的b次方 LL ret = 1; for(LL i = 1; i <= b; i ++){ ret *= a; } return ret; }
完美
可是题目是b的范围是1 <= b <= 1e9(#°Д°)
超时,妥妥的。。。
看个例子
比如计算
2*2*2*2*2*2*2*2*2*2*2
可以这样算
原式=4*4*4*4*4*2
=8*8*4*2
=16*4*2
你看,相同的可以先合并,减少计算步骤
如果题目说数据很大,还需要求余,那么代码就可以这么写
1 LL pow_mod(LL a, LL b, ll MOD){//a的b次方 2 if(b == 0) return 1; 3 LL ret = pow_mod(a * a % MOD, b/2, Mod); 5 if(b & 1) ret = ret * a % MOD; 6 return ret; 7 }
这是递归写法
然后还有递推写法
1 LL pow_mod(LL a, LL b){//a的b次方 2 LL ret = 1; 3 while(b != 0){ 4 if(b % 2 == 1){ 5 ret = (ret * a) % MOD ; 6 } 7 a = (a * a ) % MOD ; 8 b /= 2; 9 } 10 return ret; 11 }
对于位运算熟的小盆友,还可以写成位运算形式,速度又快,又好理解,在加一个求余p,代码如下
1 LL pow_mod(LL a, LL b, LL p){//a的b次方求余p 2 LL ret = 1; 3 while(b){ 4 if(b & 1) ret = (ret * a) % p; 5 a = (a * a) % p; 6 b >>= 1; 7 } 8 return ret; 9 }
有了快速幂,于是,快速乘诞生了
1 LL mul(LL a, LL b, LL p){//快速乘,计算a*b%p 2 LL ret = 0; 3 while(b){ 4 if(b & 1) ret = (ret + a) % p; 5 a = (a + a) % p; 6 b >>= 1; 7 } 8 return ret; 9 }
https://vjudge.net/contest/240113#problem/J
解释
https://blog.csdn.net/rain722/article/details/64442335
https://blog.csdn.net/wanghandou/article/details/69666620
题意:
输入n^k,输出n^k的前3位与后3位.
思路:
最后的三位可以直接快速幂取余,但要注意不够要补前导0.
求前三位则需要一些数学知识对于给定的一个数n,它可以写成10^a,其中这个a为浮点数,则n^k=(10^a)^k=10^a*k=(10^x)*(10^y);
其中x,y分别是a*k的整数部分和小数部分对于t=n^k这个数,它的位数由(10^x)决定,它的位数上的值则有(10^y)决定,因此我们
要求t的前三位,只需要将10^y求出,再乘以100,就得到了它的前三位。
fmod(x,1)可以求出x的小数部分