zoukankan      html  css  js  c++  java
  • 矩阵快速幂+实际应用--P3390 【模板】矩阵快速幂,P3938 斐波那契

    *传送1,*传送2

    矩阵并不是一个数而是可以表示一个比较复杂的模型(集合),而集合里封装着任意类型的值,而矩阵乘法则是一个比较重要的一个运算方式。

    先说一下矩阵乘法的定义:

     也就是说,结果矩阵第$m$行与第$n$列交叉位置的那个值,等于第一个矩阵第$m$行与第二个矩阵第$n$列,对应的位置的每个值的乘积之和。

    公式则是:其中$C_{ij}$为A的第$i$行与B的第$j$列对应的乘积的和,即:

    $Cij =Σaik*bkj(1<=i<=n,1<=j<=n,1<=k<=n)$。

    矩阵乘法的代码:

    const int N=100;  
    int c[N][N];  //c是最终的矩阵
    void multi(int a[][N],int b[][N],int n)  
    {  
        memset(c,0,sizeof c);  
        for(int i=1;i<=n;i++)  
            for(int j=1;j<=n;j++)  
              for(int k=1;k<=n;k++)  
                c[i][j]+=a[i][k]*b[k][j];  
    }

    快速幂

    求幂时我们常常会因结果太大而导致速度很慢,这时候我们就需要运用倍增的思想特殊的乘法应运而生————快速幂。

    举个例子,如果$a_{10}$,我们需要求十次,而如果我们用了快速幂就可以把$a_{10}$转变为二进制的形式从而加快运算速度

    引入一个定义*单位矩阵(对角线为1其余都为0,一个矩阵乘单位矩阵为它本身)

    void qpow(long long k){ 
         for(int i=1; i<=n; i++)
            I.a[i][i]=1;                                                          
        while(k>0) {                                                              
            if(k%2==1) I=I*a;
            a=a*a;
            k=k>>1;
        }
    }

    本题的完整代码:

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #define ll long long
     6 #define maxn 105
     7 #define mo 1000000007
     8 using namespace std;
     9 int n;
    10 struct mul{
    11     ll a[maxn][maxn]; 
    12 }a,I;
    13 mul operator *(const mul &x,const mul &y){     //重载运算符
    14     mul z;
    15     memset(z.a,0,sizeof(z.a));
    16     for(int k=1;k<=n;k++)
    17         for(int i=1;i<=n;i++)
    18             for(int j=1;j<=n;j++)
    19                 z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%mo)%mo;
    20     return z;
    21 }
    22 ll k;
    23 inline void init(){
    24     scanf ("%lld%lld",&n,&k);
    25     for(int i=1;i<=n;++i)
    26         for(int j=1;j<=n;++j)
    27             scanf ("%lld",&a.a[i][j]);
    28 }
    29 void qpow(long long k){ 
    30      for(int i=1; i<=n; i++)
    31         I.a[i][i]=1;                                                          
    32     while(k>0) {                                                              
    33         if(k%2==1) I=I*a;
    34         a=a*a;
    35         k=k>>1;
    36     }
    37 }
    38 int main(){
    39     init();
    40     qpow(k);
    41     for(int i=1;i<=n;++i){
    42         for(int j=1;j<=n;++j)
    43             printf("%d ",I.a[i][j]);
    44         cout<<endl;
    45     }
    46     return 0;
    47 }

    在斐波那契数列之中

    $f[i] = 1*f[i-1]+1*f[i-2]  f[i-1] = 1*f[i-1] + 0*f[i-2]$;

    所以我们可以构建一个矩阵做幂运算后,可以得到我们需要的矩阵,求得的矩阵为:

    1 1

    1 0

    所以这里我是直接求解n次幂,答案就是$a[0][1]$;

    代码如下:

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #define ll long long
     6 #define maxn 105
     7 #define mo 1000000007
     8 using namespace std;
     9 struct mul{
    10     ll a[maxn][maxn]; 
    11 }a,I;
    12 mul operator *(const mul &x,const mul &y){     //重载运算符
    13     mul z;
    14     memset(z.a,0,sizeof(z.a));
    15     for(int k=1;k<=2;k++)
    16         for(int i=1;i<=2;i++)
    17             for(int j=1;j<=2;j++)
    18                 z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%mo)%mo;
    19     return z;
    20 }
    21 ll k;
    22 inline void init(){
    23     scanf ("%lld",&k);
    24        a.a[1][1]=a.a[1][2]=a.a[2][1]=1;  
    25     a.a[2][2]=0;
    26 }
    27 void qpow(long long k){ 
    28      for(int i=1; i<=2; i++)
    29         I.a[i][i]=1;                                                          
    30     while(k>0) {                                                              
    31         if(k%2==1) I=I*a;
    32         a=a*a;
    33         k=k>>1;
    34     }
    35 }
    36 int main(){
    37     init();
    38     qpow(k);
    39     cout<<I.a[1][2];
    40     return 0;
    41 }

     

     

  • 相关阅读:
    Python中获取字典中最值对应的键
    Python中if __name__ == "__main__": 的作用
    Python中将打印输出导向日志文件
    python函数参数前面单星号(*)和双星号(**)的区别
    Python中用datetime包进行对时间的一些操作
    python中scipy.misc.logsumexp函数的运用场景
    Python中在脚本中引用其他文件函数的方法
    KS-检验(Kolmogorov-Smirnov test) -- 检验数据是否符合某种分布
    R如何检验类别变量(nominal variable)与其他变量之间的相关性
    机器学习-贝叶斯算法
  • 原文地址:https://www.cnblogs.com/very-beginning/p/12502842.html
Copyright © 2011-2022 走看看