矩阵快速幂(标准模板)

题目描述
给定n*n的矩阵A,求A^k

输入输出格式
输入格式:
第一行,n,k

第2至n+1行,每行n个数,第i+1行第j个数表示矩阵第i行第j列的元素

输出格式:
输出A^k

共n行,每行n个数,第i行第j个数表示矩阵第i行第j列的元素,每个元素模10^9+7

输入输出样例
输入样例#1:

2 1
1 1
1 1

输出样例#1:

1 1
1 1

说明
n<=100, k<=10^12, |矩阵元素|<=1000 算法:矩阵快速幂

这个题就是用到矩阵快速幂的方法 这下面的代码也是标准模板代码 就不需要改什么东西
当然这么标准的代码 肯定也是模板 代码了
矩阵运算法则
矩阵A的大小为n×m,B的大小为n×k,设C=A×B则C{i,j}= ∑ k = 1 n \sum_{k=1}^n k=1nA{i,p} ×B{p,j}

例:
矩阵乘满足结合律:(AB) C = A (BC)
有一种特殊的矩阵:单位矩阵,它从左上角到右下角的对角线上的元素均为1,除此以外全都为0。它在矩阵乘中相当于数乘中的1,即任何矩阵乘它都等于本身。

以上这些就是打出矩阵快速幂前必备的基础知识了。
代码实现
理解了矩阵乘法之后,我们就可以用函数来模拟矩阵乘了。

Mat Mul(Mat x,Mat y)
{
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
        c.m[i][j]=0;
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
        for(int k=1;k<=n;k++)
        {
            c.m[i][j]=c.m[i][j]%mod+x.m[i][k]*y.m[k][j]%mod;
          }
    return c; 
}

因为矩阵乘满足结合律,所以快速幂完全适用于矩阵,矩阵快速幂和普通快速幂几乎一模一样,不同点在于“*”号改成了Mul函数

Mat pow(Mat x,ll y)
{
Mat ans=e;
while(y)
{
    if(y&1)
     ans=Mul(ans,x);  
    x=Mul(x,x);
    y>>=1;
}
return ans;
}

知道了这些后,这道题基本就可以AC了

最后要注意开long long,不然会爆零。

AC代码:

#include<iostream>
#include<cstring>
#define mod 1000000007
#define ll long long
using namespace std;
struct Mat{
    ll m[101][101];
};//结构体存矩阵 
Mat a,e;//a是输入的矩阵,e是单位矩阵 
ll n,p;
Mat Mul(Mat x,Mat y){ //矩阵乘 
    Mat c;
    for(int i = 1;i <= n;i++)
      for(int j = 1;j <= n;j++)
        c.m[i][j] = 0;
    for(int i = 1;i <= n;i++)
      for(int j = 1;j <= n;j++)
        for(int k = 1;k <= n;k++){
            c.m[i][j] = c.m[i][j] % mod + x.m[i][k] * y.m[k][j] % mod;
          }
    return c; 
}
Mat pow(Mat x,ll y){ //矩阵快速幂 
    Mat ans = e;
    while(y){
        if(y&1){
        	ans = Mul(ans,x);         	
        }
        x = Mul(x,x);
        y >>= 1;
    }
    return ans;
}
int main(){
    //输入 
    cin >> n >> p;
    for(int i = 1;i <= n;i++){
    	for(int j = 1;j <= n;j++){
    		cin >> a.m[i][j];
    	}    	
    } 
     //算法核心     
    for(int i = 1;i <= n;i++){
        e.m[i][i] = 1;       	
    }
 
    Mat ans = pow(a,p);
    //输出 
    for(int i = 1;i <= n;i++){
        for(int j = 1;j <= n;j++){
          cout << ans.m[i][j] % mod << " ";        	
        }
        cout << endl;
    }  
    return 0;
}

例二:
大家都知道,斐波那契数列是满足如下性质的一个数列:

• f(1) = 1

• f(2) = 1

• f(n) = f(n-1) + f(n-2) (n ≥ 2 且 n 为整数)

题目描述
请你求出 f(n) mod 1000000007 的值。

输入输出格式
输入格式:
·第 1 行:一个整数 n

输出格式:
第 1 行: f(n) mod 1000000007 的值

输入输出样例
输入样例#1:
5
输出样例#1:
5
输入样例#2:
10
输出样例#2:
55
解题思路1:
根据简单的F斐波那契数列 的递归思想来做
但是 在数据大到一定程度时 ,递归思想也不能适用了 如果有一道题目让你求斐波那契数列第 n 项的值,最简单的方法莫过于直接递推了。但是如果 nn 的范围达到了 10 18 ^{18} 18级别,递推就不行了,稳 TLE。考虑矩阵加速递推。
下面的代码可以通过几个测试点:但是没有得满分

#include <bits/stdc++.h>
#define MAXN 1000001
#define MOD 1000000007
int n,i,F[MAXN];
int main(){
	scanf("%d",&n);
	F[1] = 1;
	F[2] = 1;
	for(i = 3; i <= n; i++){
		F[i] = (F[i-1] + F[i-2]) % MOD;	
	}
	printf("%d\n",F[n]);
	return 0;
}

解题思路2:
矩阵加速递推快速幂

#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007 //Mod数
struct Matrix{//这个是矩阵的结构体
    long long ma[2][2];
};
Matrix mul(Matrix A,Matrix B){//矩阵乘法
    Matrix C;//答案矩阵
    C.ma[0][0]=C.ma[0][1]=C.ma[1][0]=C.ma[1][1]=0;//初始化
    for(int i=0;i<2;i++){
        for(int j=0;j<2;j++){
            for(int k=0;k<2;k++){
                C.ma[i][j] = (C.ma[i][j] + A.ma[i][k] * B.ma[k][j]) % mod;
            }
        }
    }
    return C;
}
Matrix pow_mod(Matrix A,long long n){//卡苏米+矩阵乘法优化
    Matrix B;
    B.ma[0][0] = B.ma[1][1] = 1;
    B.ma[0][1] = B.ma[1][0] = 0;
    while(n) {
        if(n&1) B = mul(B,A);
        A = mul(A,A);
        n >>= 1;
    }
    return B;
}
int main(){
    long long n;
    cin >> n;
    Matrix A;
    A.ma[0][0] = 1;A.ma[0][1] = 1;
    A.ma[1][0] = 1;A.ma[1][1] = 0;//初始的数组
    Matrix ans = pow_mod(A,n);
    printf("%lld\n",ans.ma[0][1]);//输出答案
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值