zoukankan      html  css  js  c++  java
  • 矩阵快速幂详解

    介绍:

    矩阵乘法定义自行看百度

    矩阵快速幂顾名思义,就是把多次矩阵乘法用快速幂的形式算出,一般常用于递推的优化;

    做法:

    如果是裸的矩阵快速幂,做法非常简单,先定义一个数组记录矩阵的每个数值,在做快速幂(快速幂中相应的乘用矩阵乘法代替);

    相关题目:

    1、【模板】矩阵快速幂

    照上面的方法做就ok了;

    注意刚开始ans数组要清成单位矩阵(任何矩阵乘它不变);

     1 #include<cstdio>
     2 using namespace std;
     3 #define int long long
     4 const int MAXN=101,MOD=1000000007;
     5 int n,k,a[MAXN][MAXN],b[MAXN][MAXN],ans[MAXN][MAXN],c[MAXN][MAXN];
     6 //a数组用来记录每次的矩阵
     7 //ans数组为记录答案的数组
     8 //b作为一个暂时存放的数组 (不然每次直接更改a数组就会导致将更改过的数组相乘) 
     9 void ksm(int n,int m)//普通的快速幂 
    10 {
    11     while(m>1)
    12     {
    13         for(int i=1;i<=n;++i)
    14             for(int j=1;j<=n;++j)
    15             b[i][j]=0;
    16         if(m%2==1)
    17         {
    18             for(int i=1;i<=n;++i)
    19                 for(int j=1;j<=n;++j)
    20                 {
    21                     for(int k=1;k<=n;++k)
    22                     c[i][j]=(c[i][j]+ans[i][k]*a[k][j]%MOD)%MOD;
    23                 }
    24             for(int i=1;i<=n;++i)
    25                 for(int j=1;j<=n;++j)
    26                 ans[i][j]=c[i][j],c[i][j]=0;
    27         }
    28         for(int i=1;i<=n;++i)
    29             for(int j=1;j<=n;++j)
    30                 for(int k=1;k<=n;++k)
    31                 b[i][j]=(b[i][j]+a[i][k]*a[k][j]%MOD)%MOD;
    32         for(int i=1;i<=n;++i)
    33             for(int j=1;j<=n;++j)
    34             a[i][j]=b[i][j];
    35         m=m/2;
    36     }
    37     for(int i=1;i<=n;++i)
    38         for(int j=1;j<=n;++j)
    39         {
    40             for(int k=1;k<=n;++k)
    41             c[i][j]=(c[i][j]+ans[i][k]*a[k][j]%MOD)%MOD;
    42         }
    43     for(int i=1;i<=n;++i)
    44         for(int j=1;j<=n;++j)
    45         ans[i][j]=c[i][j],c[i][j]=0;
    46 }
    47 main()
    48 {
    49     scanf("%lld%lld",&n,&k);
    50     for(int i=1;i<=n;++i)
    51         for(int j=1;j<=n;++j) scanf("%lld",&a[i][j]);
    52     for(int i=1;i<=n;++i)
    53     ans[i][i]=1;
    54     ksm(n,k);
    55     for(int i=1;i<=n;++i)
    56     {
    57         for(int j=1;j<=n;++j)
    58         printf("%lld ",ans[i][j]%MOD);
    59         printf("
    ");
    60     }
    61     return 0;
    62 }

    2、用矩阵快速幂优化的斐波那契数列

    做法类似,斐波那契数列递推式为f[i]=f[i-1]+f[i-2];

    由f[i-2] f[i-1]推出f[i-1] f[i],把两边都看成矩阵,$1 imes 2$的矩阵$ imes $$2 imes 2$的矩阵=$1 imes 2$的矩阵,所以稍稍推算就能算出需要的矩阵;

    要求的f[n]=f[1]$ imes 矩阵 ^ n$;

    接着就用矩阵快速幂求出答案;

     1 #include<cstdio>
     2 using namespace std;
     3 #define int long long
     4 const int MAXN=101,MOD=1000000007;
     5 int n,k,a[MAXN][MAXN],ans[MAXN][MAXN],c[MAXN][MAXN];
     6 //a数组用来记录每次的矩阵
     7 //ans数组为记录答案的数组
     8 //b作为一个暂时存放的数组 (不然每次直接更改a数组就会导致将更改过的数组相乘)
     9 void ksm(int m)
    10 {
    11     while(m>1)
    12     {
    13         if(m%2==1)
    14         {
    15             for(int i=1;i<=2;++i)
    16                 for(int j=1;j<=2;++j)
    17                     for(int k=1;k<=2;++k)
    18                     c[i][j]=(c[i][j]+ans[k][j]*a[i][k]%MOD)%MOD;
    19             for(int i=1;i<=2;++i)
    20                 for(int j=1;j<=2;++j)
    21                 ans[i][j]=c[i][j],c[i][j]=0;
    22         }
    23         for(int i=1;i<=2;++i)
    24             for(int j=1;j<=2;++j)
    25                 for(int k=1;k<=2;++k)
    26                 c[i][j]=(c[i][j]+a[i][k]*a[k][j]%MOD)%MOD;
    27         for(int i=1;i<=2;++i)
    28             for(int j=1;j<=2;++j)
    29             a[i][j]=c[i][j],c[i][j]=0;
    30         m=m/2;
    31     }
    32     for(int i=1;i<=2;++i)
    33         for(int j=1;j<=2;++j)
    34         {
    35             for(int k=1;k<=2;++k)
    36             c[i][j]=(c[i][j]+ans[k][j]*a[i][k]%MOD)%MOD;
    37         }
    38     for(int i=1;i<=2;++i)
    39         for(int j=1;j<=2;++j)
    40         ans[i][j]=c[i][j],c[i][j]=0;
    41 }
    42 main()
    43 {
    44     scanf("%lld",&n);
    45     a[1][1]=0;
    46     a[2][1]=1;
    47     a[1][2]=1;
    48     a[2][2]=1;
    49     //求出的所需要的矩阵 
    50     for(int i=1;i<=2;++i)
    51     ans[i][i]=1;
    52     ksm(n-1);
    53     printf("%lld",ans[2][2]%MOD);
    54     return 0;
    55 }

    3、稍微变化的fibonacci

    同理,找出f[i-3] f[i-2] f[i-1] 变为 f[i-2] f[i-1] f[i] 的矩阵;

    再用矩阵快速幂;

     1 #include<cstdio>
     2 using namespace std;
     3 #define int long long
     4 const int MAXN=101,MOD=1000000007;
     5 int n,k,a[MAXN][MAXN],ans[MAXN][MAXN],c[MAXN][MAXN],t;
     6 //a数组用来记录每次的矩阵
     7 //ans数组为记录答案的数组
     8 //b作为一个暂时存放的数组 (不然每次直接更改a数组就会导致将更改过的数组相乘)
     9 void ksm(int m)
    10 {
    11     while(m>1)
    12     {
    13         if(m%2==1)
    14         {
    15             for(int i=1;i<=3;++i)
    16                 for(int j=1;j<=3;++j)
    17                     for(int k=1;k<=3;++k)
    18                     c[i][j]=(c[i][j]+ans[k][j]*a[i][k]%MOD)%MOD;
    19             for(int i=1;i<=3;++i)
    20                 for(int j=1;j<=3;++j)
    21                 ans[i][j]=c[i][j],c[i][j]=0;
    22         }
    23         for(int i=1;i<=3;++i)
    24             for(int j=1;j<=3;++j)
    25                 for(int k=1;k<=3;++k)
    26                 c[i][j]=(c[i][j]+a[i][k]*a[k][j]%MOD)%MOD;
    27         for(int i=1;i<=3;++i)
    28             for(int j=1;j<=3;++j)
    29             a[i][j]=c[i][j],c[i][j]=0;
    30         m=m/2;
    31     }
    32     for(int i=1;i<=3;++i)
    33         for(int j=1;j<=3;++j)
    34         {
    35             for(int k=1;k<=3;++k)
    36             c[i][j]=(c[i][j]+ans[k][j]*a[i][k]%MOD)%MOD;
    37         }
    38     for(int i=1;i<=3;++i)
    39         for(int j=1;j<=3;++j)
    40         ans[i][j]=c[i][j],c[i][j]=0;
    41 }
    42 main()
    43 {
    44     scanf("%lld",&t);
    45     for(int kk=1;kk<=t;++kk)
    46     {
    47         scanf("%lld",&n);
    48         a[1][1]=0;
    49         a[2][1]=1;
    50         a[3][1]=0;
    51         a[1][2]=0;
    52         a[2][2]=0;
    53         a[3][2]=1;
    54         a[1][3]=1;
    55         a[2][3]=0;
    56         a[3][3]=1;
    57         //求出的所需要的矩阵 
    58         for(int i=1;i<=3;++i)
    59         ans[i][i]=1;
    60         ksm(n-1);
    61         printf("%lld
    ",ans[3][3]%MOD);
    62         for(int i=1;i<=3;++i)
    63             for(int j=1;j<=3;++j)
    64             ans[i][j]=0;
    65     }
    66 }
  • 相关阅读:
    页面加载完成前的loading加载效果
    javascript数组常用的遍历方法
    JavaScript的值传递和引用传递
    操作iframe的一些方法
    函数依赖与数据库范式
    微信分享到朋友圈
    计算机原理基础-原反补
    async eachSeries如何按序列执行下去
    使用 VLOOKUP、INDEX 或 MATCH 查找值
    编码问题
  • 原文地址:https://www.cnblogs.com/JinLeiBo/p/9439607.html
Copyright © 2011-2022 走看看