矩阵快速幂求递推QAQ

本文介绍矩阵快速幂在递推求解中的应用,以斐波那契数列为例,讲解矩阵快速幂的基本原理,并提供两种实现方式:直接写矩阵乘法函数和重载运算符。

矩阵快速幂(warning:本体多次WA):
矩阵快速幂用途广泛,多用于递推求解,本文以肥波垃圾斐波那契数列为例
题解:
其实就是将矩阵运算套入到快速幂运算中,主要难点在于如何导出矩阵,如斐波那契数列中运算即为
{1110}n−2∗{f 2 f 1 }\left\{ \begin{matrix} 1&1\\1&0\end{matrix} \right\}^{n-2}*\left\{\begin{matrix} f~2~\\f~1~\end{matrix}\right\}{1110}n2{f 2 f 1 }
其中矩阵的快速幂运算有两种方式:
WA因:结构体和单位矩阵构建有问题
1.直接写矩阵乘法函数
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long ll;
//中间运算可能会超过int范围,需要long long
const int N=2;
int n,p;
ll m;
struct node{
    //结构体存储矩阵
    ll g[N+2][N+2];
}f,res;
void matrixI(node &x){
    //构造单位矩阵
    for(int i=1; i<=N; i++){
        for(int j=1; j<=N; j++)
            if(i==j) x.g[i][j]=1LL;
            else x.g[i][j]=0LL;
    }
}
void matrixMultiple(node &x,node &y,node &z){
    //矩阵乘法
    memset(z.g,0,sizeof(z.g));
    for(int i=1; i<=N; i++){
        for(int j=1; j<=N; j++) if(x.g[i][j]){
            for(int k=1; k<=N; k++){
                z.g[i][k]+=x.g[i][j]*y.g[j][k];
                if(z.g[i][k]>=m) z.g[i][k]%=m;
            }
        }
    }
}
void matrixMuli(int k){
    //快速幂运算
    matrixI(res);
    node tmp=f, t;
    while(k){
        if(k&1){
            matrixMultiple(res,tmp,t); res=t;
        }
        matrixMultiple(tmp,tmp,t); tmp=t;
        k>>=1;
    }
}
ll solve(){
    if(n<=2) return 1LL;
    matrixMuli(n-2);
    ll ret=res.g[1][1]+res.g[2][1];
    if(ret>=m) ret-=m;
    return ret;
}
int main(){
    scanf("%d%d",&n,&p);
    m=p;
    f.g[1][1]=1;
    f.g[1][2]=1;
    f.g[2][1]=1;
    f.g[2][2]=0;
    int res=(int)solve();
    printf("%d\n",res);
    return 0;
}

2.重载运算符写法
不完全代码(主函数部分没写完,但矩阵乘法的重载是完整的):

#include<bits/stdc++.h>
using namespace std;
long long Mod;
struct Matrix {
	long long c[101][101];
} A,I;
long long n,k;
Matrix operator*(const Matrix &x,const Matrix &y) {
	Matrix a;
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++)
			a.c[i][j]=0;
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n; j++)
			for(int k=1; k<=n; k++) {
				a.c[i][j]+=x.c[i][k]*y.c[k][j]%Mod;
				a.c[i][j]%=Mod;
			}
	return a;
}
int main() {
	scanf("%lld%lld",&n,&Mod);
	A.c[1][1]=A.c[1][2]=A.c[2][1]=1;
	A.c[2][2]=0;
	for(int i=1; i<=2; i++)
		I.c[i][i]=1;
	while(k>0) {
		if(k%2==1) I=I*A;
		A=A*A;
		k=k>>1;
	}
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++)
			cout<<I.c[i][j]<<' ';
		cout<<endl;
	}
	return 0;
}```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值