• 矩阵快速幂详解


    介绍:

    矩阵乘法定义自行看百度

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

    做法:

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

    相关题目:

    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 }
  • 相关阅读:
    centos linux系统日常管理3 服务管理ntsysv,chkconfig,系统日志rsyslog,last ,lastb ,exec,xargs,dmesg,screen,nohup,curl,ping ,telnet,traceroute ,dig ,nc,nmap,host,nethogs,base64,jq 第十六节课
    centos Linux系统日常管理2 tcpdump,tshark,selinux,strings命令, iptables ,crontab,TCP,UDP,ICMP,FTP网络知识 第十五节课
    一个兼职DBA的数据库运维经验 小米科技 xx@xiaomi.com 2011
    centos Linux系统日常管理1 cpuinfo cpu核数 命令 w, vmstat, uptime ,top ,kill ,ps ,free,netstat ,sar, ulimit ,lsof ,pidof 第十四节课
    HTML5矢量实现文件上传进度条
    基于HTML5的WebGL呈现A星算法3D可视化
    基于HTML5的WebGL呈现A星算法的3D可视化
    基于HTML5的WebGL设计汉诺塔3D游戏
    基于HTML5树组件延迟加载技术实现
    基于HTML5的WebGL电信网管3D机房监控应用
  • 原文地址:https://www.cnblogs.com/JinLeiBo/p/9439607.html
Copyright © 2020-2023  润新知