斐波那契(矩阵快速幂)

今天随便看了看矩阵的相关内容,顺势学习了一下矩阵构造和矩阵快速幂,然后又顺道写了这个入门题。

斐波那契数列,即Fib(n)=Fib(n1)+Fib(n2)Fib(n)=Fib(n-1)+Fib(n-2),就这么一个数列,显然可以直接递推求解,时间复杂度O(N)O(N),似乎没什么问题。

然后就遇到了这个,nn的取值范围最大是2×1092\times10^9的这么一个题,线性显然不能满足时间限制,然后就需要用矩阵快速幂求解了。

F(n)F(n)表示一个1×21\times2的矩阵[Fib(n)Fib(n+1)][Fib(n),Fib(n+1)],推道依然按照递推式,我们发现,F(n+1)F(n+1)显然就是F(n)F(n)中将第二项前移做为第一项,第一项和原第二项的和作为新的第二项(递推),即相当于每次乘以了一个2×22\times2的矩阵,我们可以求出这个矩阵是[0111] \left[ \begin{matrix} 0&1\\1&1 \end{matrix} \right]
我们记这个矩阵为ZZ

也就是说,F(1)=F(0)×ZF(1)=F(0)\times Z,相应的,F(2)=F(1)×Z=F(0)×Z×Z=F(0)×Z2F(2)=F(1)\times Z=F(0)\times Z\times Z=F(0)\times Z^2,依次类推,而我们需要求的Fib(n)Fib(n)实际上就是F(n)F(n)第一项,也就是说,只要求得了F(n)F(n),就相当于求得了Fib(n)Fib(n),于是问题就转换为了矩阵快速幂。

#include <bits/stdc++.h>
using namespace std;
int n;
const int mod = 10000;
struct p{
	int arr[3][3];
	p(){
		
	}
	p(int a[3][3]){
		for (int i = 1; i <= 2; i++){
			for (int j = 1; j <= 2; j++){
				arr[i][j] = a[i][j];
			}
		}
	}
	p operator * (const p& a){
		p temp;
		temp.arr[1][1] = this->arr[1][1] * a.arr[1][1] + this->arr[1][2] * a.arr[2][1];
		temp.arr[1][2] = this->arr[1][1] * a.arr[1][2] + this->arr[1][2] * a.arr[2][2];
		temp.arr[2][1] = this->arr[2][1] * a.arr[1][1] + this->arr[2][2] * a.arr[2][1];
		temp.arr[2][2] = this->arr[2][1] * a.arr[1][2] + this->arr[2][2] * a.arr[2][2];
		return temp;
	}
	void MOD(){
		for (int i = 0; i < 3; i++)
			for (int j = 0; j < 3; j++)
				this->arr[i][j] %= mod;
	}
};
int te[3][3];
int one[3][3];
p qpow(p temp, int n){
	p ans = p(one);
	ans.MOD();
	while (n){
		if (n & 1){
			ans = ans * temp;
			ans.MOD();
		}
		n >>= 1;
		temp = temp * temp;
		temp.MOD();
	}
	ans.MOD();
	return ans;
}
int main() {
	ios::sync_with_stdio(0);
	te[1][1] = 0, te[1][2] = te[2][1] = te[2][2] = 1;
	one[1][1] = one[2][2] = 1;
	one[1][2] = one[2][1] = 0;
	while (cin >> n && (~n)){
		p ans = qpow(p(te), n);
		cout << ans.arr[2][1] << "\n";
	}
	return 0;
}
posted @ 2020-04-09 20:45  correct  阅读(325)  评论(0)    收藏  举报