矩阵快速幂 && 求解常系数齐次线性递推式

先说矩阵A的n次幂(An)的快速幂的求法
因为矩阵乘满足结合律,所以矩阵的快速幂和前面普通快速幂原理都一样,主要在于矩阵乘法的运算

1、矩阵乘法

1.1 直接模拟矩阵乘(m行)

用结构体存矩阵(一个结构体可以直接赋值另一个结构体)

struct mat
{
    LL a[m][m];
};
mat init=mat{0,0,0,0};
mat mul(mat a,mat b)
{
     mat ans=init;
    for(int i=0; i<m; i++)
        for(int j=0; j<m; j++)
            for(int k=0; k<m; k++)
                ans.a[i][j]=(x.a[i][k]*y.a[k][j]%mod+ans.a[i][j])%mod;
     return ans;
}

所以A,B两个矩阵相乘就可以调用函数mul===>mul(A,B)

1.2 重载*号,

C++的运算符重载


mat operator *(const mat &x,const mat &y)//重载运算符
{
    mat ans=init;
    for(int i=0; i<m; i++)
        for(int j=0; j<m; j++)
            for(int k=0; k<m; k++)
                ans.a[i][j]=(x.a[i][k]*y.a[k][j]%mod+ans.a[i][j])%mod;
    return ans;
}

或者:

struct mat
{
    LL m[50][50];
    mat operator*(const mat& t) const
    {
        mat ans;
        for (int i=0; i<tot; i++)
            for (int j=0; j<tot; j++)
            {
                LL x=0;
                for (int k=0; k<tot; k++)
                    x=( m[i][k]*t.m[k][j]%mod+x )%mod;
                ans.m[i][j]=x;
            }
        return ans;
    }
};

现在A,B两个矩阵就可以直接相乘了===>A*B

2、求解常系数齐次线性递推式

在这里插入图片描述
以 Fibonacci 数列为例:
数列中 F0 = 0,F1 = 1, Fn = Fn−1 + Fn−2 ,它有两个单项式,我们就可以构造一个2行2列的矩阵,利用矩阵的乘法求Fn,我们先写出它的下一项
Fn = Fn−1 + Fn−2
Fn+1 = Fn + Fn−1
在这里插入图片描述
然后现在来填构造矩阵,因为Fn = 1* Fn−1 +1* Fn−2 ,所以第一列都是1
在这里插入图片描述
因为Fn-1 = 1* Fn−1 +0* Fn−2 ,所以第二列分别是1,0
在这里插入图片描述
然后我们用矩阵算F3
F3 = F2 + F1
F4 = F3 + F2

∣ F   2   F   1   0 0 ∣ \begin{vmatrix} F~2~ & F~1~ \\ 0&0 \\ \end{vmatrix} F 2 0F 1 0 ∣ 1 1 1 0 ∣ \begin{vmatrix} 1 &1 \\ 1&0 \\ \end{vmatrix} 1110= ∣ F   3   F   2   0 0 ∣ \begin{vmatrix} F~3~ & F~2~ \\ 0&0 \\ \end{vmatrix} F 3 0F 2 0
即:
∣ 1 1 0 0 ∣ \begin{vmatrix} 1 &1 \\ 0&0 \\ \end{vmatrix} 1010
∣ 1 1 1 0 ∣ \begin{vmatrix} 1 &1 \\ 1&0 \\ \end{vmatrix} 1110= ∣ F   3   F   2   0 0 ∣ \begin{vmatrix} F~3~ & F~2~ \\ 0&0 \\ \end{vmatrix} F 3 0F 2 0

所以Fn就等于矩阵 ∣ F   2   F   1   0 0 ∣ \begin{vmatrix} F~2~ & F~1~ \\ 0&0 \\ \end{vmatrix} F 2 0F 1 0乘以矩阵 ∣ 1 1 1 0 ∣ \begin{vmatrix} 1 &1 \\ 1&0 \\ \end{vmatrix} 1110的n-2次幂

代码:poj 3070

#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long LL;
const int mod = 1e4;
struct mat
{
    LL a[2][2];
};
mat init=mat{0,0,0,0};
mat init1=mat{1,0,0,1};//单位矩阵
mat operator *(const mat &x,const mat &y)//重载运算符
{
    mat ans=init;
    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++)
            for(int k=0; k<2; k++)
                ans.a[i][j]=(x.a[i][k]*y.a[k][j]%mod+ans.a[i][j])%mod;
    return ans;
}
mat quick_pow(mat a,LL b)
{
    mat ans=a;
    while(b)
    {
        if(b&1)
            ans=ans*a;
        a=a*a;
        b>>=1;
    }
    return ans;
}
int main()
{
    int n;
    mat a,b;
    a=mat{1,1,0,0};
    b=mat{1,1,1,0};
    while(scanf("%d",&n),n!=-1)
    {
        if(n==0)
        {
          printf("0\n");
          continue;
        }
        if(n==1||n==2)
        {
             printf("1\n");
             continue;
        }
        mat ans=a*quick_pow(b,n-3);
        printf("%lld\n",ans.a[0][0]);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值