小白回顾------矩阵快速幂讲解

本文详细介绍了快速幂的基本原理及其在取模运算中的应用,并进一步探讨了矩阵快速幂的概念与实现方法,包括矩阵乘法及快速幂的模板代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Part I:首先理解一般的快速幂
为快速求a^b,我们可以采用折半的思想:
1:当b为偶数时,a^b = = a^(b/2) * a^(b/2)
2:当b为奇数时,a^b = =a * (a^(b/2)) * (a^(b/2))

代码:

int quick_mi(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1)//奇数隔单,位运算更快,其实还可以写为,b%2==1
        {
            ans=ans*a;
        }
        a=a*a;//偶数折半
        b=b>>1;//位运算折半,其实还可以写为b=b/2
    }
    return ans;
}

拓展快速幂取模:
1:根据数学公式:a*b%m=(a%m)*(b%m)%m

代码:

int quick_mi(int a,int b,int c)
{
    int ans=1;
    while(b)
    {
        if(b&1)//奇数隔单
        {
            ans=ans*a%c;
        }
        a=a*a%c;//偶数折半
        b=b>>1;
    }
    return ans;
}

Part II:矩阵快速幂
1:令MAT为一任意矩阵,求MAT^n:
2:需要定义一个结构体,去方便我们调用矩阵
代码:

struct MATI//定义一个结构体类型,可以定义矩阵
    {
        int a[2][2];//这里我们用最简单的矩阵为例
    };

3:首先我们需要构造矩阵乘法MAT*MAT
代码:

 MATI MX(MATI A,MATI B)//定义矩阵乘法
    {
    
        MATI C;
        for(int i=0;i<=2;i++)
        {
            for(int j=0;j<2;j++)
            {
                for(int k=0;k<2;k++)
                {
                    C.a[i][j]+=(A.a[i][k]*B.a[k][j]);
                }
            }
        }
        return C;//返回的矩阵即相乘所得
    }

4:得到矩阵乘法后,我们模仿快速幂写法即可
代码:

MATI MX_MI(MATI D,int N)
{
    MATI RE;
    memset(RE.a,0,sizeof(RE.a));
    for(int i=0; i<2; i++)
        RE.a[i][i]=1;//定义初等矩阵
    while(N)
    {

        if(N&1)
            RE=MX(RE,D);
        D=MX(D,D);
        N=N>>1;

    }
    return RE;
}

提醒:
定义矩阵时候需手动输入值,对于新定义的矩阵需要初始化

矩阵快速幂模板:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=2;
ll tmp[N][N],res[N][N];
void multi(ll a[][N],ll b[][N],int n)
{
    memset(tmp,0,sizeof(tmp));
    for(ll i=0;i<n;i++)
    {
	   for(ll j=0;j<n;j++)
	   {
        for(ll k=0;k<n;k++)
        {
        tmp[i][j]+=(a[i][k]*b[k][j])%mod;
        }
        tmp[i][j]=tmp[i][j]%mod;
      }
   }
    for(ll i=0;i<n;i++)
        for(ll j=0;j<n;j++)
        a[i][j]=tmp[i][j];
}
void Pow(ll a[][N],ll m,int n)
{
    memset(res,0,sizeof(res));//m是幂,n是矩阵大小
    for(ll i=0;i<n;i++) res[i][i]=1;
    while(m)
    {
	    if(m&1)
        multi(res,a,n);//res=res*a;复制直接在multi里面实现了;
        multi(a,a,n);//a=a*a
        m>>=1;
    }
}
int main()
{
     ll m;
     int n;
     ll a[N][N];
    while(~scanf("%lld",&m))
    {
         n=2;
    	a[0][0]=1,a[0][1]=1,a[1][0]=1,a[1][1]=0;
		Pow(a,m,n);
 	   printf("%lld\n",res[1][0]);
	}
   return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值