矩阵快速幂模板和构造

矩阵快速幂

矩阵快速幂其实原理上和快速幂是一样的,只不过基数是一个矩阵。常用于解决常系数齐次线性递推式一类的问题,这类问题通常需要自己构造矩阵。

下面举两个例子:
1.先是最简单的Fibonacci数列, f ( n ) = f ( n 1 ) + f ( n 2 ) , f ( 1 ) = f ( 2 ) = 1 f(n)=f(n-1)+f(n-2),f(1)=f(2)=1 ,求第n项,当n非常大的时候按原来的递推已经不能解决了,时间上不允许,空间上也不允许。
[ f ( n 1 ) f ( n 2 ) 0 0 ] [ a b c d ] = [ f ( n ) f ( n 1 ) 0 0 ] \begin{bmatrix} f(n-1) & f(n-2) \\ 0 & 0 \\ \end{bmatrix}* \begin{bmatrix} a & b \\ c & d \\ \end{bmatrix}=\begin{bmatrix} f(n) & f(n-1) \\ 0 & 0 \\ \end{bmatrix} ,左边的矩阵第一行放 f ( n ) f(n) 的各项,右边的矩阵第一行放 f ( n + 1 ) f(n+1) 的各项,注意 f ( n ) f(n) n n 项加起来,构造出来的就是 n n n*n 的矩阵。
求解矩阵 [ a b c d ] \begin{bmatrix} a & b \\ c & d \\ \end{bmatrix} 满足上式
\bullet 构造方法:
在这里插入图片描述其中 [ 1 1 1 0 ] n 2 \begin{bmatrix} 1 & 1 \\ 1 & 0 \\ \end{bmatrix}^{n-2} 就能用矩阵快速幂解决了。
2.再来一个: f ( n ) = ( a f ( n 1 ) + b f ( n 2 ) ) % p , f ( 1 ) = f ( 2 ) = 1 f(n)=(a*f(n-1)+b*f(n-2))\%p,f(1)=f(2)=1 ,求第n项。
思路和上一个一样:
在这里插入图片描述注意:因为每次都要取模p,所以要求 b a % p \frac{b}{a}\%p ,就要求出a关于p的逆元,还要注意的的是最后得出来的矩阵的 a 11 a_{11} 项要除以a才是 f ( n ) f(n) ,此时又要求逆元。。。
\bullet 最后码上矩阵快速幂的模板:
求Fibonacci数列第n项

#include<cstdio>
#include<set>
#include<map>
#include<string.h>
#include<string>
#include<vector>
#include<iostream>
#include<queue>
#include<algorithm>
typedef long long LL;
using namespace std;
const int maxn=1e6+5;
const int mod=10000;

struct node
{
    LL mat[2][2];
    node(LL a,LL b,LL c,LL d){
        mat[0][0]=a;
        mat[0][1]=b;
        mat[1][0]=c;
        mat[1][1]=d;
    }
};

node operator * (node a,node b)//重载*号
{
    node ans(0,0,0,0);
    LL sum=0;
    for(int i=0;i<2;i++){
        for(int j=0;j<2;j++){
            sum=0;
            for(int k=0;k<2;k++){
                sum+=(a.mat[i][k]%mod*b.mat[k][j]%mod)%mod;
                sum%=mod;
            }
            ans.mat[i][j]=sum;
        }
    }
    return ans;
}

node POW(node a,LL b)
{
    node ans(1,0,0,1);
    while(b){
        if(b&1)ans=ans*a;
        a=a*a;
        b>>=1;
    }
    return ans;
}

int main()
{
    LL n;
    while(scanf("%lld",&n)&&n!=-1){
        node a(1,1,1,0);
        node ans=POW(a,n);
        printf("%lld\n",ans.mat[0][1]);
    }
    return 0;
}
发布了34 篇原创文章 · 获赞 7 · 访问量 1892

猜你喜欢

转载自blog.csdn.net/qq_43628761/article/details/95521770