1. 程式人生 > >矩陣快速冪優化遞推式 例:斐波那契數列

矩陣快速冪優化遞推式 例:斐波那契數列

首先是一點基礎知識:

① 矩陣相乘的規則:矩陣與矩陣相乘 第一個矩陣的列數必須等於第二個矩陣的行數 假如第一個是m*n的矩陣 第二個是n*p的矩 陣則結果就是m*p的矩陣且得出來的矩陣中元素具有以下特點:

第一行第一列元素為第一個矩陣的第一行的每個元素和第二個矩陣的第一列的每個元素乘積的和 以此類推 第i行第j列的元素就是第一個矩陣的第i行的每個元素與第二個矩陣第j列的每個元素的乘積的和。

② 單位矩陣: n*n的矩陣 mat ( i , i )=1; 任何一個矩陣乘以單位矩陣就是它本身 n*單位矩陣=n, 可以把單位矩陣等價為整數1。(單位矩陣用在矩陣快速冪中)

例如下圖就是一個7*7的單位矩陣:

對於矩陣乘法與遞推式之間的關係:

如:在斐波那契數列之中

fi[i] = 1*fi[i-1]+1*fi[i-2] fi[i-1] = 1*f[i-1] + 0*f[i-2];

所以

矩陣快速冪:

因為矩陣乘法滿足結合律,原因如下


所以,我們可以用類似數字快速冪的演算法來解決矩陣快速冪。(前提:矩陣為n*n的矩陣,原因見矩陣乘法定義)

程式碼

Matrix fast_pow(Matrix a, int x) {
	Matrix ans;
	ans.x = a.x;
	for(int i = 0; i < ans.x; i++)
		ans.a[i][i] = 1;
	while(x) {
		if(x&1) 
			ans = ans*a;
		a = a*a;
		x >>= 1;
	}
	return ans;
}

用矩陣快速冪求斐波那契數列的第N項的程式碼:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;

const int M = 1e9+7;

struct Matrix {
	long long a[2][2];
	Matrix() {
		memset(a, 0, sizeof(a));
	}
	Matrix operator * (const Matrix y) {
		Matrix ans;
		for(int i = 0; i <= 1; i++)
			for(int j = 0; j <= 1; j++)	
				for(int k = 0; k <= 1; k++)	
					ans.a[i][j] += a[i][k]*y.a[k][j];
		for(int i = 0; i <= 1; i++)
			for(int j = 0; j <= 1; j++)
				ans.a[i][j] %= M;
		return ans;
	}
	void operator = (const Matrix b) {
		for(int i = 0; i <= 1; i++)
			for(int j = 0; j <= 1; j++)
				a[i][j] = b.a[i][j];
	}
};

int solve(long long x) {
	Matrix ans, trs;
	ans.a[0][0] = ans.a[1][1] = 1;
	trs.a[0][0] = trs.a[1][0] = trs.a[0][1] = 1;
	while(x) {
		if(x&1) 
			ans = ans*trs;
		trs = trs*trs;
		x >>= 1;
	}
	return ans.a[0][0];
}

int main() {
	int n;
	scanf("%d", &n);
	cout << solve(n-1) << endl;
	return 0;
}