问题背景:
给定N,M,求Fn % m的结果。
F[0]=0;
F[1]=1;
F[n]=F[n-1]+F[n-2], for n>1
如果用公式递推,由于n很大,超过Int的范围并且递推时间复杂度是O(n).
解题思路:
- Fibonacci数列的矩阵表示:
,矩阵的初始值是
- 因此需要求矩阵的幂,问题分解为两部分,矩阵乘法 + 快速幂;采用【快速幂】的方法,原理如下:
当b 为偶数时,a^b =a^(b/2) * a^(b/2),
当b 为奇数时,a^b =a*a^(b-1)
所以问题就转化为求a^(b/2)
<pre name="code" class="cpp">matrix fastMod(int n) { if(n == 1) return base; /*matrix temp = base; matrix ans; ans[0][0] = ans[1][1] = 1; ans[0][1] = ans[1][0] =0; while(n){ <span> </span>if( n & 1) //如果n是奇数 <span> </span>ans = multiply(temp, ans); <span> </span>n >>= 1; //相当于n除以2 <span> </span>temp = multiply(temp, temp); } return temp; <span> </span>}非递归方法*/ if(n & 1) return multiply(base, fastMod(n-1)); else{ matrix temp = fastMod(n>>1); return multiply(temp, temp); } }
数据结构:
struct matrix{
int m[2][2];
}base; //Fibonacci数列矩阵乘法表示的初始值
代码如下:
#include<iostream>
#include<vector>
using namespace std;
struct matrix{
int arr[2][2];
}base; //Fibonacci数列矩阵乘法表示的初始值
int m;
//矩阵乘法函数
matrix multiply(matrix a, matrix b)
{
matrix temp;
temp.arr[0][0] = (a.arr[0][0]*b.arr[0][0] + a.arr[0][1]*b.arr[1][0]) % m;
<span style="white-space:pre"> </span>temp.arr[0][1] = (a.arr[0][0]*b.arr[0][1] + a.arr[0][1]*b.arr[1][1]) % m;
<span style="white-space:pre"> </span>temp.arr[1][0] = (a.arr[1][0]*b.arr[0][0] + a.arr[1][1]*b.arr[1][0]) % m;
<span style="white-space:pre"> </span>temp.arr[1][1] = (a.arr[1][0]*b.arr[0][1] + a.arr[1][1]*b.arr[1][1]) % m;
return temp;
}
matrix fastMod(int n)
{
if(n == 1)
return base;
/*matrix temp = base;
matrix ans;
ans[0][0] = ans[1][1] = 1; ans[0][1] = ans[1][0] =0;
while(n){
<span style="white-space:pre"> </span>if( n & 1) //如果n是奇数
<span style="white-space:pre"> </span>ans = multiply(temp, ans);
<span style="white-space:pre"> </span>n >>= 1; //相当于n除以2
<span style="white-space:pre"> </span>temp = multiply(temp, temp);
}
return temp;
<span style="white-space:pre"> </span>}非递归方法*/
if(n & 1)
return multiply(base, fastMod(n-1));
else{
matrix temp = fastMod(n>>1);
return multiply(temp, temp);
}
}
int main()
{
int t;
unsigned int n;
//matrix ans;
cin >> t;
while(t--){
cin >> n >> m;
if(n==0)
cout << 0 << endl;
else{
//初始赋值
base.arr[0][0] = base.arr[0][1] = base.arr[1][0] = 1;
base.arr[1][1] = 0;
cout << fastMod(n).arr[0][1] % m << endl;
}
}
return 0;
}