矩阵快速幂 ——(递推表达式)

 矩阵快速幂

 

 首先知道矩阵 

     矩阵(Matrix)是一个按照长方阵列排列的复数实数集合;

     矩阵乘法:

定义:设 A
 m×p 
的矩阵, B
 p×n 
的矩阵,那么称
 m×n 
的矩阵 C为矩阵 AB的乘积,记作
 C=A×B
,其中矩阵C中的第
 i 
行第
 j 
列元素可以表示为:



知道矩阵乘法之后,比如菲波那切数列就是一个递推式,
    F(n)=F(n-1)+F(n-2); 因为矩阵乘法,所以

设 矩阵 A为 
                 
矩阵 B 为
                  
则  A*B  则为    F(n)=        F(n-1)*1+F(n-2)*1
因为我们需要的矩阵为  A*B  的矩阵为  
                               
所以倒推到 B 矩阵 ,则 B矩阵是     ,
所以 F(n) 的矩阵为  初始矩阵   *   (B^(n-2))   n>=3;
所得到的矩阵  A[0][0]  就是F(n) 的值,时间复杂度优化的地方就是在幂指数的那部分快速幂,节约了时间。
所以关键就在于  从 递推式构造矩阵 
比如:

这个构造出来的矩阵就是

       自己可以写出这个矩阵,就明白了;下面给一个简单的题目,练练手。                                                                                                               



给一个简单的练习题:   点击打开链接

#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <string>
#include <bitset>
#include <vector>
#include <iostream>
#include <algorithm>
#include <stdlib.h>


using namespace std;
typedef long long LL;
const int INF=2e9+1e8;
const int MOD=1000007;
const int MAX_SIZE=1005;
const int MM=3;


LL f1,f2,a,b,c,n;


struct Mat
{
    LL maze[MM][MM];
    void set_empty()
    {
        memset(maze,0,sizeof(maze));
    }
};
Mat unit_Mat=
{
    1,0,0,
    0,1,0,
    0,0,1
};   //  定义一个单位矩阵,任何一个矩阵 乘以 单位矩阵,其值等于本身;
Mat operator *(Mat a,Mat b)  // 重载运算符  * //  定义两个矩阵的乘法,根据矩阵乘法的定义来写
{
    Mat c;
    c.set_empty();  // 一定要设置为空。清零数组;不然后面加等一个数会有垃圾值
    LL i,j,k;
    for(i=0; i<MM; i++)
    {
        for(j=0; j<MM; j++)
        {
            for(k=0; k<MM; k++)
            {
                c.maze[i][j]+=a.maze[i][k] * b.maze[k][j];
                c.maze[i][j] %= MOD;
            }
        }
    }
    return c;
}
Mat operator^(Mat a,LL N)  //  优化时间的就在此处,
//  类似与一般的int 数字的快速幂求值,思想是一样的。不懂可百度快速幂。
{
    Mat c=unit_Mat;
    while(N)
    {
        if(N&1) c=a*c;
        a=a*a;
        N>>=1;
    }
    return c;
}
void solve()
{
    Mat A,B;
    B.set_empty();
    A.set_empty();
    B.maze[0][0]=b,B.maze[1][0]=a,B.maze[2][0]=c;
    B.maze[0][1]=B.maze[2][2]=1;
    B=B^(n-2);
    A.maze[0][0]=f2,A.maze[0][1]=f1,A.maze[0][2]=1;
    LL ans=0;
    Mat C=A*B;
    printf("%lld\n",(C.maze[0][0]+MOD)%MOD);
}
int main()
{
    int times;
    scanf("%d",&times);
    while(times--)
    {
        scanf("%lld %lld %lld %lld %lld %lld",&f1,&f2,&a,&b,&c,&n);
        if(n == 1)
            printf("%lld\n",(f1+MOD)%MOD);
        else if(n == 2)
            printf("%lld\n",(f2+MOD)%MOD);
        else solve();  // 其上位特判 因为公式的定义域是  n>=3;
    }
    return 0;
}


转载于:https://www.cnblogs.com/coded-ream/p/7207987.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值