关于矩阵快速幂

矩阵快速幂,顾名思义,是将快速幂算法运用到矩阵中,已达到时间优化的目的。

先来康康快速幂算法。

如果要求解x的n次方,例如7的10次方,当我们用pow函数时要进行10次计算,但当我们把10二进制化,即为(1010),则该计算结果可化为7的(1000)次方乘以7的(10)次方,即7的8次方乘7的平方,7的8次方可以经过7的平方乘以7的平方得到7的四次方,然后7的四次方乘以7的四次方得到7的八次方,总共只需要四次计算即可算出7的10次方,起到了减少计算次数的目的。

那么快速幂的模板如下:

int qpow(int m, int n)//m为底数,n为指数
{
int ans = 1;
while (n)
{
if (n & 1) ans = ans * m;//判断m是奇数还是偶数,即m转化为二进制后最低位是1还是0
m = m * m;
n >>= 1;//m的二进制数右移一位
}
return ans;
}

 

矩阵的快速幂原理是一样的,下面用三个例题来说明一下。(往往用到矩阵快速幂的题目的难点在于矩阵的构造)

首先是矩阵快速幂,可以记为模板https://www.luogu.com.cn/problem/P3390

AC代码如下:

#include<iostream>
using namespace std;
const int N = 110;
typedef long long ll;
struct mat
{
    ll m[N][N];
};
mat a, b,c,ans;
ll n, m;
mat mul(mat a, mat b)
{
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            c.m[i][j] = 0;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            for (int k = 0; k < n; k++)
                c.m[i][j] = c.m[i][j]%(1000000007)+a.m[i][k]*b.m[k][j]%(1000000007);//矩阵乘法
    return c;
}
void qpow(mat a, ll m)
{
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            ans.m[i][j] = 0;
    for(int i=0;i<n;i++) ans.m[i][i]=1;
    while (m)
    {
        if (m & 1) ans = mul(a, ans);
        a = mul(a, a);
        m >>= 1;
    }
}//将快速幂运用于矩阵
int main()
{
    cin >> n >> m;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            cin >> a.m[i][j];
    qpow(a, m);
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            cout << ans.m[i][j]%(1000000007) << ' ';
        }
        cout << endl;
    }
}

 

 

第二题是斐波那契数列。https://www.luogu.com.cn/problem/P1962

矩阵构造过程如下:

 

 

 

AC代码实现如下:

 1 #include<iostream>
 2 using namespace std;
 3 typedef long long ll;
 4 ll mod=1000000007;;
 5 struct mat
 6 {
 7     ll m[100][100];
 8 };
 9 mat a,c, ans;
10 mat mul(mat a, mat b)
11 {
12     for(int i=0;i<2;i++)
13     for(int j=0;j<2;j++)
14     c.m[i][j]=0;
15     for (int i = 0; i < 2; i++)
16         for (int j = 0; j < 2; j++)
17             for (int k = 0; k < 2; k++)
18                 c.m[i][j] =c.m[i][j]%mod+(a.m[i][k] * b.m[k][j])%mod;
19     return c;
20 }
21 mat qpow(mat a, ll n)
22 {
23     for (int i = 0; i < 2; i++)
24         for (int j = 0; j < 2; j++)
25             ans.m[i][j] = 0;
26     for (int i = 0; i <2; i++) ans.m[i][i] = 1;
27     while (n)
28     {
29         if (n & 1) ans = mul(ans, a);
30         a = mul(a, a);
31         n >>= 1;
32     }
33     return ans;
34 }
35 int main()
36 {
37     cin.tie(0);
38     cout.tie(0);
39     ll num;
40     cin >> num;
41     a.m[0][0] = a.m[0][1] = a.m[1][0] = 1;
42     a.m[1][1] = 0;
43     mat aw=qpow(a,num-1);
44     if(num>=3) cout << aw.m[0][0]%mod << endl;
45     else cout<<1<<endl;
46     return 0;
47 
48 }

第三题.POJ3233  Given a n × n matrix A and a positive integer k, find the sum S = A + A2 + A3 + … + Ak.

矩阵推导过程如下:

 

 AC代码如下:

#include<iostream>
using namespace std;
const int N = 110;
typedef long long ll;
struct mat
{
    ll m[N][N];
};
mat a, b,c,ans;
ll n, m,k;
mat mul(mat a, mat b)
{
    for (int i = 0; i < 2*n; i++)
        for (int j = 0; j < 2*n; j++)
            c.m[i][j] = 0;
    for (int i = 0; i < 2*n; i++)
        for (int j = 0; j < 2*n; j++)
            for (int k = 0; k < 2*n; k++)
                c.m[i][j] = c.m[i][j]%m+a.m[i][k]*b.m[k][j]%m;
    return c;
}
void qpow(mat a, int m)
{
    for (int i = 0; i < 2*n; i++)
        for (int j = 0; j < 2*n; j++)
            ans.m[i][j] = 0;
    for(int i=0;i<2*n;i++) ans.m[i][i]=1;
    while (m)
    {
        if (m & 1) ans = mul(a, ans);
        a = mul(a, a);
        m >>= 1;
    }
}
int main()
{
    cin>>n>>k>>m;
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    a.m[i][j]=0;
    for(int i=0;i<n;i++)
    a.m[i][i]=1;
    for(int i=n;i<2*n;i++)
    for(int j=0;j<n;j++)
    a.m[i][j]=0;
    for(int i=0;i<n;i++)
    for(int j=n;j<2*n;j++)
    cin>>a.m[i][j],a.m[i+n][j]=a.m[i][j];
    qpow(a,k);
    for(int i=0;i<n;i++)
    {
        for(int j=n;j<2*n;j++)
        {
            cout<<ans.m[i][j]%m<<' ';
        }
        cout<<endl;
    }
    return 0;
}

 

posted @ 2022-02-12 12:45  王小美O(∩_∩)O  阅读(237)  评论(0)    收藏  举报