矩陣快速冪詳解


介紹:

矩陣乘法定義自行看百度

矩陣快速冪顧名思義,就是把多次矩陣乘法用快速冪的形式算出,一般常用於遞推的優化;

做法:

如果是裸的矩陣快速冪,做法非常簡單,先定義一個數組記錄矩陣的每個數值,在做快速冪(快速冪中相應的乘用矩陣乘法代替);

相關題目:

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("\n");
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 \times 2$的矩陣$ \times $$2 \times 2$的矩陣=$1 \times 2$的矩陣,所以稍稍推算就能算出需要的矩陣;

要求的f[n]=f[1]$ \times 矩陣 ^ 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\n",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 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM