快速幂:快速计算某个数的幂次( )html
快速幂时间复杂度为 ,相比朴素的 快了不少ios
它的基本原理是把 n 转换为二进制,如 web
核心:反复平方法,即 不断把底数平方
算法
int fastpow(int a, int k, int p) { int res = 1; while (k) { if (k & 1) res = res * 1ll * a % p; a = a * 1ll * a % p; k >>= 1; } return res; }
计算 a 的 k 次,若是 k 为偶数(不为0),则先计算 ,而后平方;若是 k 是奇数,则先计算 ,而后在乘以 a;递归的出口是 编程
int fastpow(int a, int k, int p) { if (k == 0) return 1 % p; if (k & 1) return fastpow(a, k - 1, p) * 1ll * a % p; else { // 必须用临时遍历tmp存,不然算法退回到O(n) int tmp = fastpow(a, k / 2, p); return tmp * 1ll * tmp % p; } }
说明:递归快速幂思路比较简单,但要注意 须要用临时遍历存下来,不然算两次,会让算法退回到 复杂度app
注:快速幂因为过于简单,一般做为某个复杂算法的中间一步,好比欧拉公式,欧几里得算法svg
875. 快速幂函数
LeetCode 题解 | 50. Pow(x, n)(快速幂 C++)学习
数学问题:矩阵n次方的七种求法的概括——在本科数学时学过里面的几种方法
上面说的是数学方法,在计算机编程中常常用快速幂来求矩阵的 n 次幂
矩阵快速幂适合于求递推式 ,加速递推公式
特别是当 n 很大时,它能在 级别的时间复杂度内求出第 n 项,如求斐波那契数列的第1e9项
显然当咱们算出 后, 的值就都算出来了(这算法是否是很牛逼!)
咱们用一个结构体来封装矩阵,这样能够简化不少代码,让程序看上去更舒服
struct mat{ int m[N][N]; mat() { // 用构造函数初始化成 单位矩阵E memset(m, 0, sizeof m); for (int i = 0; i < N; i ++) m[i][i] = 1; } }
矩阵快速幂函数(和普通快速幂相似)
mat fastpow(mat a, int k) { // 矩阵快速幂 mat res; while (k) { if (k & 1) res = multi(res, a); a = multi(a, a); k >>= 1; } return res; }
结构体(存矩阵) + 矩阵乘法 + 矩阵快速幂
#include <iostream> using namespace std; const int N = 100, mod = 1e6; int n, k; struct mat { int m[N][N]; mat() { // 用构造函数初始化成 单位矩阵E memset(m, 0, sizeof m); for (int i = 0; i < N; i++) m[i][i] = 1; } }; // 矩阵乘法 mat multi(mat a, mat b) { mat c; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { c.m[i][j] = 0; for (int k = 0; k < n; k++) { c.m[i][j] += a.m[i][k] * b.m[k][j]; // 累加 } c.m[i][j] %= mod; } } return c; } // 矩阵快速幂(核心) mat fastpow(mat a, int k) { mat res; while (k) { if (k & 1) res = multi(res, a); a = multi(a, a); k >>= 1; } return res; } int main() { cin >> n >> k; // 输入矩阵阶数 n 和幂次 k mat a, res; // 输入矩阵 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { cin >> a.m[i][j]; } } res = fastpow(a, k); // 输出结果 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { cout << res.m[i][j] << " "; } cout << endl; } }
输入
3 10 -1 1 0 -4 3 0 1 0 2
输出
-19 10 0 -40 21 0 -1003 1013 1024
将 n=10 代入通项 ,能够知道咱们的代码是正确的
说明:通常题目给的数据会很大,因此都会取 mod
POJ 题解 | 3070.Fibonacci 求斐波那契数列的第 n 项(矩阵快速幂 C++)
分析能够获得
k为偶数:
k为奇数:
能够用矩阵快速幂来求,而后再递归 sum 便可
POJ 题解 | 3233. Matrix Power Series(矩阵快速幂 C++)
关键在于构造出递推的矩阵
能够理解为选定一组基
在全部的 n 位正数中,有多少个数含有偶数个3,有多少个数含有奇数个3?
注:
参考:https://zhuanlan.zhihu.com/p/137677246
因为计算机底层设计的缘由,作加法每每比乘法快的多,所以将乘法转换为加法计算将会大大提升乘法运算的速度
除此以外,当咱们计算 的时候,每每较大的数计算 会超出 long long int 的范围,这个时候使用快速乘法方法也能解决上述问题。
快速乘法的原理:利用乘法分配率来将 转化为多个式子相加的形式求解
例如:
typedef long long ll; ll qmm(ll a, ll b, ll mod) { ll ans = 0; while (b) { if (b & 1) ans = (ans + a) % mod; a <<= 1; // 20*1->20*2->20*4->20*8 b >>= 1; } return ans; }
[1] 数论之矩阵快速幂
[2] 算法学习笔记(4):快速幂 - 知乎
[3] 算法竞赛模板 快速乘与快速幂 - Kannyi - 博客园
[4] 二分幂,快速幂,矩阵快速幂,快速乘