定义矩阵乘法: C=AB
如果
A
是
其中
Cik=∑nk=1AijBjk
,如:
[142536]⎡⎣⎢135246⎤⎦⎥=[1+6+154+15+302+8+188+20+36]=[22492864]
矩阵乘法满足结合律,不满足交换律。
单位矩阵
In
:
In=⎡⎣⎢⎢⎢⎢⎢10⋮001⋮0⋯⋯⋱⋯00⋮1⎤⎦⎥⎥⎥⎥⎥
矩阵乘法及快速幂:
struct Matrix{
int m[M][M];
Matrix(){
memset(m,0,sizeof(m));
}
void Init(){//初始化单位矩阵
for(int i=1;i<=n;i++)
m[i][i]=1;
}
Matrix operator *(const Matrix &a)const{
Matrix res;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
if(!m[i][j])continue;
for(int k=1;k<=n;k++)
res.m[i][k]+=m[i][j]*a.m[j][k];
}
return res;
}
};
Matrix Pow(Matrix x,int t){
Matrix res;
res.Init();
while(t){
if(t&1)res=res*x;
x=x*x;
t>>=1;
}
return res;
}
POJ3070 Fibonacci
Task:
求斐波那契数列第n位取模P的值。(P=10000,n<=1000000000)
Solution:
首先直接循环是O(n)的。
考虑矩阵快速幂:
[f[n]f[n−1]]=[1110][f[n−1]f[n−2]]
[f[n]f[n−1]]=[1110]n−1[f[1]f[0]]=[1110]n−1[10]设为An−1B
于是将这个矩阵
A
快速幂,就可以在
#include<stdio.h>
#include<string.h>
#define M 5
#define P 10000
const int n=2;
struct Matrix{
int m[M][M];
Matrix(){
memset(m,0,sizeof(m));
}
void Init(){//初始化单位矩阵
for(int i=1;i<=n;i++)
m[i][i]=1;
}
Matrix operator *(const Matrix &a)const{
Matrix res;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
if(!m[i][j])continue;
for(int k=1;k<=n;k++)
res.m[i][k]=(res.m[i][k]+m[i][j]*a.m[j][k])%P;
}
return res;
}
};
Matrix Pow(Matrix x,int t){
Matrix res;
res.Init();
while(t){
if(t&1)res=res*x;
x=x*x;
t>>=1;
}
return res;
}
int main(){
Matrix B;
B.m[1][1]=1;B.m[2][1]=0;
while(1){
int d;
scanf("%d",&d);
if(d==-1)break;
if(!d){
puts("0");
continue;
}
Matrix A;
A.m[1][1]=A.m[1][2]=A.m[2][1]=1;A.m[2][2]=0;
A=Pow(A,d-1);
A=A*B;
printf("%d\n",A.m[1][1]);
}
return 0;
}