前言
线性代数中的矩阵乘法对写编程有帮助,比如矩阵快速幂求斐波那契数列第n项之类的,所以我们要去稍微学习一些相关的运算
一.矩阵乘法的计算
运算规则:Cij = sum(Aik * Bkj)
对于两个矩阵Aij和Bnm
当且仅当j==n时,AB有意义,且结果矩阵为Cim
根据运算规则可以写成其代码
#include<bits/stdc++.h>
using namespace std;
int A[10][10],B[10][10],C[10][10];
int main(){
int a,b,c,d;
cin>>a>>b>>c>>d;
for(int i=1;i<=a;i++){
for(int j=1;j<=b;j++){
cin>>A[i][j];
}
}
for(int i=1;i<=c;i++){
for(int j=1;j<=d;j++){
cin>>B[i][j];
}
}
if(b!=c)cout<<"boring";
else{
for(int i=1;i<=a;i++){
for(int j=1;j<=d;j++){
for(int k=1;k<=b;k++){
C[i][j]+=A[i][k]*B[k][j];
}
}
}
for(int i=1;i<=a;i++){
for(int j=1;j<=d;j++){
cout<<C[i][j]<<" ";
}
cout<<endl;
}
}
return 0;
}
矩阵快速幂
求Am
矩阵乘法满足矩阵快速幂求Am
类似的用非递归形式写快速幂即可,只不过原来的数变成了矩阵,普通的数相乘变成了矩阵乘法
#include<stdio.h>
#include<iostream>
using namespace std;
const int N=105;
const int p=1e9+7;
long long a[N][N],b[N][N];
long long ans[N][N],n;
void build_ans() {
for(int i=1; i<=n; i++)ans[i][i]=1;
}
void build_a(){
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
cin>>a[i][j];
}
}
}
void chen_ans() {
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++)b[i][j]=ans[i][j];
}//拷贝一个ans给b
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
ans[i][j]=0;
for(int k=1; k<=n; k++) {
ans[i][j]=(ans[i][j]+a[i][k]*b[k][j])%p;
}
}
}
}
void chen_a() {
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++)b[i][j]=a[i][j];
}//拷贝一个a给b
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
a[i][j]=0;
for(int k=1; k<=n; k++) {
a[i][j]=(a[i][j]+b[i][k]*b[k][j])%p;
}
}
}
}
void ksm(long long m) {
build_ans();//建立一个单位矩阵ans(AE=EA=A)
build_a();
while(m) {
if(m%2)chen_ans();
chen_a();
m/=2;
}
}
int main() {
long long m;//求方阵A的m次方
cin>>n>>m;
ksm(m);
return 0;
}
二.实际用处
1.求斐波那契数列第n项
根据矩阵乘法可构造出方阵
a[1][1]=0
a[1][2]=1
a[2][1]=1
a[2][2]=1
代码如下
#include<stdio.h>
#include<iostream>
using namespace std;
const int N=105;
const int p=1e9+7;
long long a[N][N],b[N][N];
long long ans[N][N],n;
void build_ans() {
for(int i=1; i<=2; i++)ans[i][i]=1;
}
void build_a(){
a[1][1]=0;
a[1][2]=1;
a[2][1]=1;
a[2][2]=1;
}
void chen_ans() {
for(int i=1; i<=2; i++) {
for(int j=1; j<=2; j++)b[i][j]=ans[i][j];
}
for(int i=1; i<=2; i++) {
for(int j=1; j<=2; j++) {
ans[i][j]=0;
for(int k=1; k<=2; k++) {
ans[i][j]=(ans[i][j]+a[i][k]*b[k][j])%p;
}
}
}
}
void chen_a() {
for(int i=1; i<=2; i++) {
for(int j=1; j<=2; j++)b[i][j]=a[i][j];
}
for(int i=1; i<=2; i++) {
for(int j=1; j<=2; j++) {
a[i][j]=0;
for(int k=1; k<=2; k++) {
a[i][j]=(a[i][j]+b[i][k]*b[k][j])%p;
}
}
}
}
void ksm(long long n) {
build_ans();
build_a();
while(n) {
if(n%2)chen_ans();
chen_a();
n/=2;
}
}
int main() {
long long m;//斐波那契数列第n项
cin>>n;
ksm(n);
cout<<(ans[1][1]+ans[2][1])%p;
return 0;
}
2. x n x_n xn=(t * x n − 1 x_{n-1} xn−1+p)%mod1%mod2,求第n项
扫描二维码关注公众号,回复:
13121354 查看本文章

构造A
a[1][1]=t
a[1][2]=0
a[2][1]=1
a[2][2]=1
快速幂即可~
【注意】因为long long mod炸范围了,需要使用慢速乘防爆
#include<bits/stdc++.h>
using namespace std;
long long ans[5][5],a[5][5],b[5][5];
long long mod1,mod2,t,p;
long long mul(long long x,long long y){
long long res=0;
while(y){
if(y%2)res=(res+x)%mod1;
x=(x+x)%mod1;
y/=2;
}
return res;
}
void build_ans(){
ans[1][1]=1;
ans[2][2]=1;
}
void build_a(){
a[1][1]=t;
a[1][2]=0;
a[2][1]=1;
a[2][2]=1;
}
void chen_ans(){
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++)b[i][j]=ans[i][j];
}
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++){
ans[i][j]=0;
for(int k=1;k<=2;k++){
ans[i][j]=(ans[i][j]+mul(b[i][k],a[k][j]))%mod1;
}
}
}
}
void chen_a(){
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++)b[i][j]=a[i][j];
}
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++){
a[i][j]=0;
for(int k=1;k<=2;k++){
a[i][j]=(a[i][j]+mul(b[i][k],b[k][j]))%mod1;
}
}
}
}
void ksm(unsigned long long n){
build_ans();
build_a();
while(n){
if(n%2)chen_ans();
n/=2;
chen_a();
}
}
int main(){
long long n,x0;
cin>>mod1>>t>>p>>x0>>n>>mod2;
ksm(n);
cout<<(mul(x0,ans[1][1])+mul(p,ans[2][1]))%mod1%mod2;
return 0;
}
3
例题3
同理构造,详解略
#include<bits/stdc++.h>
using namespace std;
long long a[4][4],ans[4][4],b[4][4],p=1e9+7;
void chen_ans(){
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++)b[i][j]=ans[i][j];
}
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
ans[i][j]=0;
for(int k=1;k<=3;k++){
ans[i][j]=(ans[i][j]+b[i][k]*a[k][j])%p;
}
}
}
}
void chen_a(){
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++)b[i][j]=a[i][j];
}
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
a[i][j]=0;
for(int k=1;k<=3;k++){
a[i][j]=(a[i][j]+b[i][k]*b[k][j])%p;
}
}
}
}
void ksm(long long n){
a[1][1]=1;
a[1][2]=1;
a[1][3]=0;
a[2][1]=0;
a[2][2]=0;
a[2][3]=1;
a[3][1]=1;
a[3][2]=0;
a[3][3]=0;
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
if(i==j)ans[i][j]=1;
else ans[i][j]=0;
}
}
while(n){
if(n%2)chen_ans();
chen_a();
n=n/2;
}
cout<<ans[2][3]<<endl;
}
int main() {
long long T,n;
cin>>T;
while(T--){
cin>>n;
ksm(n+3);
}
return 0;
}
同理构造,详解略
#include<bits/stdc++.h>
using namespace std;
long long a[4][4],ans[4][4],b[4][4],p;
void chen_ans(){
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++)b[i][j]=ans[i][j];
}
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++){
ans[i][j]=0;
for(int k=1;k<=2;k++){
ans[i][j]=(ans[i][j]+b[i][k]*a[k][j])%p;
}
}
}
}
void chen_a(){
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++)b[i][j]=a[i][j];
}
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++){
a[i][j]=0;
for(int k=1;k<=2;k++){
a[i][j]=(a[i][j]+b[i][k]*b[k][j])%p;
}
}
}
}
void ksm(long long n){
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++){
if(i==j)ans[i][j]=1;
else ans[i][j]=0;
}
}
while(n){
if(n%2)chen_ans();
chen_a();
n=n/2;
}
}
int main() {
long long t,c,a1,a2,n;
cin>>t>>c>>a1>>a2>>n>>p;
t%=p;
c%=p;
a[1][1]=t;
a[1][2]=1;
a[2][1]=c;
a[2][2]=0;
if(n==1){
cout<<a1%p;
return 0;
}
ksm(n-1);
cout<<(a2*ans[1][2]+a1*ans[2][2])%p;
return 0;
}