快速幂+矩阵快速幂入门(举列斐波数列)

快速幂

计算a的b次幂对c取模!

我们能想到的就是暴力;

循环b次,每次乘以a就得到了答案;

但是如果b的值很大呢?这种O(n)的算法就太慢了!

下面-快速幂上场

首先了解一下下面这两个公式

 

https://i-blog.csdnimg.cn/blog_migrate/1ed3b133426c129528df2cd331ab571a.png

接下来先直接给你们贴代码

int PowerMod(int a, int b, int c)//计算a的b次幂对c取模(复杂度lgb)

  {

    int ans = 1;

    a = a % c;

    while(b>0)

    {  

      if(b % 2 = = 1)

      ans = (ans * a) % c;

       b = b/2;

      a = (a * a) % c;

      }

  return ans;

  }

是不是很神奇?为什么就变成了logn复杂度呢?其实关键在于b=b/2;为什么要这样写呢??我举个例子

我们要计算2^8,按照先前的算法我们需要循环8次。快速幂就是:计算2的4次幂可以由2的2次幂乘以2的2次幂,八次幂就是由二的四次幂乘以二的四次幂!!!!!!(懂了吗兄弟???当你数字很大的时候就是奇效!!你可以用手写一个很大的数按照快速幂算法算一下  复杂度不高的  一定要试试你才会体会到快速幂的奥妙)

矩阵快速幂

好难理解啊。。。好吧不吓唬你,其实入门还是很简单的!!

首先你需要有点线代基础知识!!(既然我写出来了我就给你来点矩阵快速幂需要的线代基础知识)

矩阵是什么你应该知道!!对!你肯定知道!我不会告诉你矩阵就是一个二维数组只是他有自己的一套运算规律

加减都是位置对应得的一项直接相加减

乘法如下(不一样)

举例:A、B均为3*3的矩阵:C=A*B,下面的代码会涉及到两种运算顺序,第一种就是直接一步到位求,第二种就是每次求一列,比如第一次,C00+=a00*b00,C01+=a00*b01……第二次C00+=a00*b10,C01+=a01*b11……以此类推。。。

C00 = a00*b00 + a01*b10 + a02*b20
C01 = a00*b01 + a01*b11 + a02*b21 
C02 = a00*b02 + a01*b12 + a02*b22
C10 = a10*b00 + a11*b10 + a12*b20
C11 = a10*b00 + a11*b11 + a12*b21
C12 = a10*b02 + a11*b12 + a12*b22
C20 = a20*b00 + a21*b10 + a22*b20
C21 = a20*b01 + a21*b11 + a22*b21
C22 = a20*b02 + a21*b12 + a22*b22

C00 = a00*b00 + a01*b10 + a02*b2

C01 = a00*b01 + a01*b11 + a02*b21 
C02 = a00*b02 + a01*b12 + a02*b22

(注释一下AB是矩阵A和矩阵B相乘,a是A的元素,aij是位置【i,j】的值,b自己类比)

 

好了下面那开始讲解矩阵快速幂(仅仅入门  难点的我做个几十道题了再发出来)

首先你要构造一个单位的矩阵(我也不知道怎么构造,因为这个没有板子,只能靠题目来构造,这个是我觉得矩阵快速幂唯二难得地方)

单位矩阵: n*n的矩阵 mat ( i , i )=1; 任何一个矩阵乘以单位矩阵就是它本身 n*单位矩阵=n, 可以把单位矩阵等价为整数1。(单位矩阵用在矩阵快速幂中)

7*7的单位矩阵

快速幂的思路就是:

设A为矩阵,求A的N次方,N很大,随便你怎么大1000000好吧。

先看小一点的,A的9次方

A^9

= A*A*A*A*A*A*A*A*A  【一个一个乘,要乘9次】

= A*(A*A)*(A*A)*(A*A)*(A*A)【保持格式的上下统一,所以加上这句】

 = A*(A^2)^4 【A平方后,再四次方,还要乘上剩下的一个A,要乘6次】

= A*((A^2)^2)^2【A平方后,再平方,再平方,还要乘上剩下的一个A,要乘4次】

 

也算是一种二分思想的应用吧,1000000次幂,暴力要乘1000000次,快速幂就只要(log2底1000000的对数) 次。懂了吗??你肯定都懂!!

好了对于斐波数列(别tm给我说你不知道这个数列)我就直接上代码了(代码上有很详细的解释)

#include<bits/stdc++.h>///我图省事才写的万能头文件(不建议,做题多一点的都知道有的oj打不开)
using namespace std;
typedef long long ll;
const int MOD=10000;
struct mat
{
    ll a[2][2];///自行改变,要用多大看题目
};
mat mat_mul(mat x,mat y)///矩阵相乘返回一个矩阵
{
    mat res;///需要返回的用于存储积的矩阵
    memset(res.a,0,sizeof(res.a));///清零无需多言
    for(int i=0;i<2;i++)///小于2是由你的二维数组大小决定
        for(int j=0;j<2;j++)
        for(int k=0;k<2;k++)
        res.a[i][j]=(res.a[i][j]+x.a[i][k]*y.a[k][j]);///前两个循环是为了确定下来所求矩阵元素,最后一个循环元素位置相关然后累加
       ///res.a[i][j]%=mod///取模,看题目需不需要
    return res;
}
///求一个矩阵n次幂(参照求n的m次幂一样)
void mat_pow(int n)
{
    mat c,res;
    c.a[0][0]=c.a[0][1]=c.a[1][0]=1;
    c.a[1][1]=0;
    memset(res.a,0,sizeof(res.a));
    for(int i=0;i<2;i++) res.a[i][i]=1;
    while(n)
    {
        if(n&1) res=mat_mul(res,c);
        c=mat_mul(c,c);
        n=n>>1;
    }
    printf("%I64d\n",res.a[0][1]);
}
int main()
{
    int n;
    while(~scanf("%d",&n)&&n!=-1)
    {
        mat_pow(n);
    }
    return 0;
}
 

我知道你肯定想知道为什么要单位矩阵啊??为什么

我告诉你,因为他是多维的!

给你摆一个东西你自己体会一下

好了  你肯定懂了  bb!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值