快速幂(拓展移位运算,二进制的理解)
分治的方法
// 求:b^p// 思路:// 任意一个数p,可以表示成 p = 2 * p/2 + p%2// b^(2 * p/2 + p%2),就可以拆开后,递归调用f(p/2),递归终止边界是p == 0, return 1;
// 求2^b#include <iostream>using namespace std;int f(int b){if (b == 0) return 1;int t = f(b / 2);if (b & 1) return t * t * 2;else return t * t;}int main(){int a, b;cin >> b;cout << f(b) << '\n';return 0;}
// 求a^b#include <iostream>using namespace std;typedef long long ll;int f(int a, int b){if (b == 0) return 1;ll t = f(a, b / 2);if (b & 1) return t * t * a;else return t * t;}int main(){int a, b;cin >> a >> b;cout << f(a, b) << '\n';return 0;}
移位运算的方法
根据数学常识,每一个正整数可以唯一表示为若干个指数不重复的2的次幂的和。如果b在二进制下有k位,其中第i位的数字是,那么
于是:
因为向上取整,所以上式乘积项的数量不多于k个,
又因为
所以,通过k次递推求出每个乘积项,当时,把该乘积项累积到答案中。
b & 1 运算可以取出 b 在二进制表示下的最低位, 而 b >> 1 运算可以舍去最低位,在递推的过程中将二者结合,就可以遍历 b 在二进制表示下的所有数字 。时间复杂度是
。
// 求 a^k mod p,时间复杂度 O(logk)// 模板请记忆// 写法1int qmi(int a, int k, int p){int res = 1;while (k) //当k不是0的时候{if (k & 1) res = (LL)res * a % p;k >>= 1;a = (LL)a * a % p;}return res;}// 写法2int power(int a, int b, int p){int ret = 1;for (; b; b >>= 1){if (b & 1) ret = 1ll * ret * a % p;a = 1ll * a * a % p;}return ret;}
//upd20220331int power(int a, int b, int p){int ret = 1;while (b){if (b & 1) ret = ret * a % p;b >>= 1;a = 1ll * a * a % p;}}// 洗牌// https://iai.sh.cn/problem/610// 结合倍增,ST表// f[N][30];是预处理出来的ST表int cur = i, b = k, t = 0;while (b){if (b & 1) cur = f[cur][t]; // 第二维,就是在枚举二进制位t++, b >>= 1;}
例题,取余运算(mod)
输入b,p,k的值,求 b^p mod k 的值。其中b,p,k为长整型数。
例题,2011
通过测试发现,2011的n次方的结果,每500个数一循环。1次方、501次方、1001……结果一样。2次方,502次方,1002次方……结果一样。所以,尽管指数可能有200位,只需要考虑最后的3位指数就可以了。如果指数n不足3位,直接计算2011的n次方结果mod 10000就行了。
