ACM数论——快速幂
快速幂定义:
顾名思义,快速幂就是快速算底数的n次幂。其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高。
原理:
以下以求a的b次方来介绍:
把b转换成二进制数。该二进制数第i位的权为
例如
11的二进制是1011
11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1
因此,我们将a¹¹转化为算
快速幂位运算:
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 }
快速乘:
为了防止求的时候溢出,通常会使用一种叫做“快速乘”的算法。
LL mul(LL a, LL b, LL p){//快速乘,计算a*b%p LL ret = 0; while(b){ if(b & 1) ret = (ret + a) % p; a = (a + a) % p; b >>= 1; } return ret; }
具体拿一个题目来示例,题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5187
这个题先找规律,然后在求快速乘法和快速幂结合起来。题目推出来通式是:2n-2
#include<iostream> #include <cstdio> using namespace std; typedef long long LL; LL fast_multi(LL m, LL n, LL mod)//快速乘法 { LL ans = 0;//注意初始化是0,不是1 while (n) { if (n & 1) ans += m; m = (m + m) % mod;//和快速幂一样,只不过这里是加 m %= mod;//取模,不要超出范围 ans %= mod; n >>= 1; } return ans; } LL fast_pow(LL a, LL n, LL mod)//快速幂 { LL ans = 1; while (n) { if (n & 1) ans = fast_multi(ans, a, mod);//不能直接乘 a = fast_multi(a, a, mod); ans %= mod; a %= mod; n >>= 1; } return ans; } int main() { LL n, p; while (~scanf("%I64d %I64d", &n, &p)) { if (n == 1)//特判一下 { printf("%I64d\n", 1 % p); continue; } printf("%I64d\n", (fast_pow(2, n, p) - 2 + p) % p);//这一步注意,不要为负数 } return 0; }