矩阵乘法——矩阵快速幂

矩阵乘法怎么乘

设让矩阵 a a a 乘矩阵 b b b 得到矩阵 c c c,那么 c c c 的第 i i i 行第 j j j 个元素的值就等于 a a a 的第 i i i 行与 b b b 的第 j j j 列上对应元素相乘的和。

举个例子:
( 1 2 3 4 ) ∗ ( 4 3 2 1 ) = ( a b c d ) \left( \begin{array}{c} 1 & 2 \\ 3 & 4 \end{array} \right) * \left( \begin{array}{c} 4 & 3 \\ 2 & 1 \end{array} \right)= \left( \begin{array}{c} a & b\\ c & d\\ \end{array} \right) (1324)(4231)=(acbd)
那么对于 a a a 的值,就是第一个矩阵的第一行 ( 1 , 2 ) (1,2) (1,2) 和第二个矩阵的第一列 ( 4 , 2 ) (4,2) (4,2) 的对应元素相乘的和,也就是 a = 1 × 4 + 2 × 2 = 8 a=1\times 4+2\times 2=8 a=1×4+2×2=8
再比如 c c c 的值, c = 3 × 4 + 4 × 2 = 20 c=3\times 4+4\times 2=20 c=3×4+4×2=20
最后的结果是:
( 1 2 3 4 ) ∗ ( 4 3 2 1 ) = ( 8 5 20 13 ) \left( \begin{array}{c} 1 & 2 \\ 3 & 4 \end{array} \right) * \left( \begin{array}{c} 4 & 3 \\ 2 & 1 \end{array} \right)= \left( \begin{array}{c} 8 & 5\\ 20 & 13\\ \end{array} \right) (1324)(4231)=(820513)
可以看出,得到的矩阵 c c c 的行数就是矩阵 a a a 的行数,列数就是矩阵 b b b 的列数。

矩阵乘法的限制

上面提到, c c c 的每一个元素都是矩阵 a a a 某一行与矩阵 b b b 的某一列元素对应元素的乘积的和,那么就有一个限制,就是 a a a 的行要能与 b b b 的列相对应,换句话说, a a a 的列数与 b b b 的行数要相同,否则是做不了矩阵乘法的。

矩阵乘法的性质

矩阵乘法不满足交换律,这个比较显然。

但是结合律和分配律还是满足的。(想想就明白了)

其他东西

矩阵乘法,其实也可以理解为向量乘向量,矩阵 a a a 乘矩阵 b b b,可以将 a a a 的每一行视为一个向量,这个向量的维度就是 a a a 的列数, b b b 的每一列是一个向量,维度为 b b b 的行数, a b ab ab 相乘得到的矩阵 c c c 其实就是 a a a b b b 包含的向量两两的点积,所以要求 a a a 的列数与 b b b 的行数相同。

据说矩阵是为了给线性方程组一个更方便的表示方法,假如有这样一个线性方程组:
{ 2 x + y = 5 x − y = 1 \begin{cases} 2x+y=5\\ x-y=1 \end{cases} {2x+y=5xy=1
用矩阵表示就是这个样子:
( 2 1 1 − 1 ) ∗ ( x y ) = ( 5 1 ) \left( \begin{array}{c} 2 & 1\\ 1 &-1 \end{array} \right)* \left( \begin{array}{c} x\\ y \end{array} \right)= \left( \begin{array}{c} 5\\ 1 \end{array} \right) (2111)(xy)=(51)

用处:

可以用来加速方程的递推。

很经典的, f i b o n a c c i fibonacci fibonacci 数列, f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n)=f(n-1)+f(n-2) f(n)=f(n1)+f(n2),那么发现要得出下一项的值的话只需要前两个数即可,那么可以先搞出下面这个矩阵:
( f ( x − 1 ) f ( x − 2 ) ) \left( \begin{array}{c} f(x-1)\\ f(x-2) \end{array} \right) (f(x1)f(x2))
那么,我们下一步,就是要把这个矩阵变成下面这个矩阵:
( f ( x ) f ( x − 1 ) ) \left( \begin{array}{c} f(x)\\ f(x-1) \end{array} \right) (f(x)f(x1))
很显然,只需要让这个矩阵乘上原来的矩阵即可:
( 1 1 1 0 ) \left( \begin{array}{c} 1 & 1\\ 1 & 0 \end{array} \right) (1110)
计算过程:
( 1 1 1 0 ) ∗ ( f ( x − 1 ) f ( x − 2 ) ) = ( f ( x ) f ( x − 1 ) ) \left( \begin{array}{c} 1 & 1\\ 1 & 0 \end{array} \right)* \left( \begin{array}{c} f(x-1)\\ f(x-2) \end{array} \right)= \left( \begin{array}{c} f(x)\\ f(x-1) \end{array} \right) (1110)(f(x1)f(x2))=(f(x)f(x1))

那么,要求 f ( n ) f(n) f(n) 的话,只需要让 ( f ( 2 ) f ( 1 ) ) \left( \begin{array}{c}f(2)\\f(1)\end{array}\right) (f(2)f(1))被乘 n − 2 n-2 n2 ( 1 1 1 0 ) \left( \begin{array}{c}1 & 1\\1 & 0\end{array}\right) (1110) 即可。
又因为,矩阵乘法满足结合律,所以可以使用快速幂。
于是,用快速幂求出 ( 1 1 1 0 ) n − 2 \left( \begin{array}{c}1 & 1\\1 & 0\end{array}\right)^{n-2} (1110)n2 然后再乘上 ( f ( 2 ) f ( 1 ) ) \left( \begin{array}{c}f(2)\\f(1)\end{array}\right) (f(2)f(1)) 即可。
代码:

#include 
#include 
#define ll long long
#define mod 1000000007ll

struct matrix{
    int w,h;
    ll a[10][10];
    matrix()
    {
        memset(a,0,sizeof(a));
    }
    matrix operator *(matrix x)
    {
        matrix re;re.h=h;re.w=x.w;
        for(int i=1;i<=re.h;i++)
        for(int j=1;j<=re.w;j++)
        for(int k=1;k<=w;k++)
        re.a[i][j]+=a[i][k]*x.a[k][j],re.a[i][j]%=mod;
        return re;
    }
};

ll n;

int main()
{
    scanf("%lld",&n);
    ll m=n-2;
    matrix a,b;
    a.w=1;a.h=2;
    a.a[1][1]=1;
    a.a[2][1]=1;
    b.w=2;b.h=2;
    b.a[1][1]=b.a[1][2]=b.a[2][1]=1;
    matrix ans;ans.w=-1;
    while(m>0)//快速幂
    {
        if(m%2==1)
        {
            if(ans.w==-1)ans=b;
            else ans=ans*b;
        }
        b=b*b;
        m/=2;
    }
    if(n<3)printf("1");
    else printf("%lld\n",(ans*a).a[1][1]);
}
例题

【XR-1】分块 题解

你可能感兴趣的:(数论)