1.快速幂(fast power)
one 定义.
快速幂(fast power),及快速算底数的n次幂。其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高。
two 原理.
举例:计算2的64次方
如果按平常的方法,那要乘63次,可是用快速幂只要五次。
计算方法:2^64=2^32*2^32
=(2^16*2^16)*(2^16*2^16)
=((8^8*2^8)*(2^8*2^8))*((2^8*2^8)*(2^8*2^8))
=(((2^4*2^4)*(2^4*2^4))*((2^4*2^4)*(2^4*2^4)))*(((2^4*2^4)*(2^4*2^4))*((2^4*2^4)*(2^4*2^4)))
three 基本思路
(1)当b是奇数时,那么有 a^b = a * a^*(b-1)
(2)当b是偶数时,那么有 a^b = a^(b/2) * a^(b/2)
Four 实现
1.递归
typedef long long ll;
ll binaryPow(ll a, ll b, ll m){
if(b == 0) return 1;
else if(b % 2 == 1) return a * binaryPow(a, b - 1, m) % m;
else{
ll num = binaryPow(a, b/2, m) % m;
return num * num % m;
}
}
2.非递归
long long binpow(long long a, long long b) {
long long res = 1;
while (b > 0) {
if (b & 1) res = res * a;
a = a * a;
b >>= 1;
}
return res;
}
five 例题
解析:可以看出是求2^(n-1),用快速幂
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#define p 1000000007
using namespace std;
long long ans=2,n;
void qpow(long long k) {
long long f=1;
while(k>1) {
if(k%2!=0) f=(ans*f)%p,k--;
if(k) ans=(ans*ans)%p,k/=2;
}
ans=(ans*f)%p;
}
int main() {
scanf("%lld",&n);
qpow(n-1);
printf("%lld",ans);
}
高精度快速幂:求2^(p-1) 的最后一百位
#include <bits/stdc++.h>
using namespace std;
int a[505], b[505], t[505], i, j;
int mult(int x[], int y[]) // 高精度乘法
{
memset(t, 0, sizeof(t));
for (i = 1; i <= x[0]; i++) {
for (j = 1; j <= y[0]; j++) {
if (i + j - 1 > 100) continue;
t[i + j - 1] += x[i] * y[j];
t[i + j] += t[i + j - 1] / 10;
t[i + j - 1] %= 10;
t[0] = i + j;
}
}
memcpy(b, t, sizeof(b));
}
void ksm(int p) // 快速幂
{
if (p == 1) {
memcpy(b, a, sizeof(b));
return;
}
ksm(p / 2); //(2^(p/2))^2=2^p
mult(b, b); // 对b平方
if (p % 2 == 1) mult(b, a);
}
int main() {
int p;
scanf("%d", &p);
a[0] = 1; // 记录a数组的位数
a[1] = 2; // 对2进行平方
b[0] = 1; // 记录b数组的位数
b[1] = 1; // 答案数组
ksm(p);
for (i = 100; i >= 1; i--) {
if (i == 1) {
printf("%d\n", b[i] - 1); // 最后一位减1
} else
printf("%d", b[i]);
}
}
2.矩阵快速幂
1.基础知识:矩阵乘法
简单的说矩阵就是二维数组,数存在里面,矩阵乘法的规则:A*B=C
乘法规则如下:
其中c[i][j]为A的第i行与B的第j列对应乘积的和
可以知道使用矩阵乘法的复杂度为O(n^3),e于是就想到了快速幂,两者结合,就有了矩阵快速幂。方法很简单,把快速幂算法中的乘法改成矩阵的乘法就可以了
2.例题 斐波那契数列
首先假设Fn为斐波那契数列第n项,矩阵Fib(n)=[Fn Fn−1],矩阵base=
a | b |
c | d |
给出一个矩阵公式
Fib(n)=Fib(n−1)∗baseFib(n)=Fib(n−1)∗base
[FnFn−1]=[Fn−1Fn−2]∗[acbd][FnFn−1]=[Fn−1Fn−2]∗[abcd]
{a∗Fn−1+c∗Fn−2=Fnb∗Fn−1+d∗Fn−2=Fn−1{a∗Fn−1+c∗Fn−2=Fnb∗Fn−1+d∗Fn−2=Fn−1
显然由上式可计算出base=
1 | 1 |
1 | 0 |
公式:Fib[n]=[1,1]*base^(n-2)
代码:
#include <iostream>
#include <cstring>
#define Max_rank 3
#define mod 1000000007
struct Matrix {
long long a[Max_rank][Max_rank];
Matrix() {
memset(a, 0, sizeof(a));
}
void init(){
a[1][1] = a[1][2] = a[2][1] = 1;
a[2][2] = 0;
}
Matrix operator*(const Matrix b) {
Matrix res;
for (int i = 1; i <= 2; i++)
for (int j = 1; j <= 2; j++)
for (int u = 1; u <= 2; u++)
res.a[i][j] = (res.a[i][j] + a[i][u]*b.a[u][j])%mod;
return res;
}
};
long long q_pow(long long n){
Matrix ans,base;
ans.init();
base.init();
while(n > 0){
if(n&1) ans =ans *base;
base = base *base;
n >>= 1;
}
return ans.a[1][1];
}
int main() {
long long n;
while(std::cin >> n){
std::cout << q_pow(n-2) << std::endl;
}
return 0;
}
参考资料:
快速幂算法(c语言)_是一帆哦!的博客-CSDN博客_c语言快速幂