快速幂和矩阵快速幂

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=

ab
cd


给出一个矩阵公式

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=

11
10

公式: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语言快速幂

快速幂 - OI Wiki

矩阵快速幂(原理+模板)_Learning_is_endless的博客-CSDN博客_矩阵快速幂

矩阵快速幂(原理+模板)_Learning_is_endless的博客-CSDN博客_矩阵快速幂

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值