矩阵快速幂

矩阵乘法

矩阵相乘最重要的方法是一般矩阵乘积。它只有在第一个矩阵的列数(column)和第二个矩阵的行数(row)相同时才有意义。一般单指矩阵乘积时,指的便是一般矩阵乘积。一个m×n的矩阵就是m×n个数排成mn列的一个数阵。由于它把许多数据紧凑的集中到了一起,所以有时候可以简便地表示一些复杂的模型。

定义:

A  的矩阵,B  的矩阵,那么称  的矩阵C为矩阵AB的乘积,记作 ,其中矩阵C中的第行第 列元素可以表示为:

 

如下所示:

 

注意事项

当矩阵A的列数等于矩阵B的行数时,AB可以相乘。

① 矩阵C的行数等于矩阵A的行数,C的列数等于B的列数。

② 乘积C的第m行第n列的元素等于矩阵A的第m行的元素与矩阵B的第n列对应元素乘积之和。

想要掌握矩阵快速幂就要先知道什么是矩阵求法。

 

矩阵快速幂求法:

若求mⁿ的值,若用常用方法。即:m*m*m*m*m*m.......时间复杂度为On),若n的数值很大的话,会很耗时,若用快速幂求法就耗时少多了时间复杂度为O(n)

例:m^7=m^1112)。思想就是把幂指数转化为二进制。例子只需要循环3就可以求出答案.

实现:

while(n)

{

    if(n&1)//判断二进制末尾是否与1相同。

        abs*=m;//ans用来记录结果初始为0.

    m*=m;

    n>>=1;(二进制数向右移一位,也可写为n/=2)

}

这行该很好理解就不做进一步讲解。若何活用矩阵快速幂才是最重要的。

例:

若 x < 10 f(x) = x.
I若x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10);
ai(0<=i<=9) 是0或者 1

输入km

输出fk)若大于m=取其模。

大神说这是一道做基础的快速幂的题,因为他是一个裸题,不用推导公式。

我们可以用类似数字快速幂的算法来解决矩阵快速幂。

代码实现:

#include<iostream>

#include<string.h>

#include<cstdio>

#include<algorithm>

#define N 10

int arr[N],f[N];

int k,MOD;

struct Found

{

    long long mat[N][N];

    Found(){

        memset(mat,0,sizeof(mat));

    }

    Found operator*(const Found& m)const{

        Found tmp;

        for(int i=0;i<N;i++){

            for(int j=0;j<N;j++){

                    tmp.mat[i][j]=0;

                for(int k=0;k<N;k++)

                {

                    tmp.mat[i][j]+=m.mat[i][k]*mat[k][j]%MOD;

                    tmp.mat[i][j]%=MOD;

                }

            }

        }

        return tmp;

    }

};

long long pow(Found& m,int k)

{

    Found ans;

    memset(ans.mat,0,sizeof(ans.mat));

    for(int i=0;i<N;i++)

    {

        ans.mat[i][i]=1;

    }

    k-=9;

    while(k)

    {

        if(k&1)

            ans=ans*m;

        m=m*m;

        k>>=1;

    }

    long long sum=0;

    for(int i=0;i<N;i++)

    {

        sum+=(f[N-i-1]*ans.mat[0][i])%MOD;

        sum%=MOD;

    }

    return sum;

}

void init(Found& m)

{

    memset(m.mat,0,sizeof(m.mat));

    for(int i=0;i<N;i++)

        m.mat[0][i]=arr[i];

    for(int i=0;i<N-1;i++)

        m.mat[i+1][i]=1;

    for(int i=0;i<N;i++)

        f[i]=i;

}

int main()

{

    Found m;

    while(scanf("%d%d",&k,&MOD)!=EOF)

    {

        for(int i=0;i<N;i++)

            scanf("%d",&arr[i]);

        init(m);

        if(k<10)

            printf("%d",k);

        else

            printf("%lld\n",pow(m,k));

    }

}

利用矩阵快速幂求:斐波那契数列Fibonacci sequence)。

在斐波那契数列之中

fi[i] = 1*fi[i-1]+1*fi[i-2] 

fi[i-1] = 1*f[i-1] + 0*f[i-2];

所以


具体代码实现:

#include<cstdio>

#include<algorithm>

#include<cstring>

#include<iostream>

const int MOD=1e+7;

int f[2]={1,1};

using namespace std;

struct Found

{

    long long mat[2][2];

    Found(){

        memset(mat,0,sizeof(mat));

    }

    Found operator*(const Found& m)const{

        Found tmp;

        for(int i=0;i<2;i++){

            for(int j=0;j<2;j++){

                    tmp.mat[i][j]=0;

                for(int k=0;k<2;k++)

                {

                    tmp.mat[i][j]+=m.mat[i][k]*mat[k][j]%MOD;

                    tmp.mat[i][j]%=MOD;

                }

            }

        }

        return tmp;

    }

};

long long pow(int k)

{

    Found m,ans;

    m.mat[0][0]=m.mat[0][1]=m.mat[1][0]=1;

    m.mat[1][1]=0;

    ans.mat[0][0]=ans.mat[1][1]=1;

    k=k-2;

    while(k)

    {

        if(k&1)

            ans=ans*m;

        m=m*m;

        k>>=1;

    }

    return ans.mat[0][0]*f[1]+ans.mat[0][1]*f[0];

}

int main()

{

    int k;

    while(scanf("%d",&k)!=EOF)

    {

        if(k>2)

            printf("%lld\n",pow(k));

        else

            printf("1\n");

    }

}

不得不提下对于2*2矩阵的阶乘,仔细分析就是Fibonacci sequence数列,可以利用这点使上述代码简化。

弄了很久才搞明白,虽然消耗很长时间时间,但对矩阵快速幂理解更深了,矩阵快速幂的分享就到这里了,理解它是第一步,下一步做的就是独立练习这方面的题型,使知识更加的牢固。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值