所以有gcd(1+Sm,1+Sn)=Fgcd(m+2,n+2).用辗转相除法求最大公约数,用矩阵快速幂得到斐波那契数第 k 项。
斐波那契数列:又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1, F(n)=F(n-1)+F(n-2)(n>=2,n∈N*).
通项公式 an=(1/√5)*{[(1+√5)/2]^n - [(1-√5)/2]^n}
奇数项求和 f(1)+f(3)+f(5)+…+f(2n-1)=f(2n)
偶数项求和 f(2)+f(4)+f(6)+…+f(2n) =f(2n+1)-1
平方求和 [f(0)]^2+[f(1)]^2+…+[f(n)]^2=f(n)·f(n+1)
两倍项关系 f(2n)/f(n)=f(n-1)+f(n+1)
——百度百科
矩阵快速幂:利用矩阵乘法的结合律,来减少重复计算的次数,高效地计算矩阵的高次方的。
例子:把n个矩阵进行两两分组,比如:A*A*A*A*A*A => (A*A)*(A*A)*(A*A)。这样变的好处是,你只需要计算一次A*A,然后将结果(A*A)连乘自己两次就能得到A^6,即(A*A)^3=A^6。算一下发现这次一共乘了3次,少于原来的5次。
对本题有矩阵
#include
#include
#include
#include
using namespace std;
long long p;
struct matrix{
long long a[2][2];
}origin,res;
void init(){ //初始化单位矩阵和要连乘的矩阵
origin.a[0][0]=1;
origin.a[0][1]=1;
origin.a[1][0]=1;
origin.a[1][1]=0;
res.a[0][0]=1;
res.a[0][1]=0;
res.a[1][0]=0;
res.a[1][1]=1;
}
matrix multiply(matrix x,matrix y) //矩阵乘法
{
matrix temp;
memset(temp.a,0,sizeof(temp.a));
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
temp.a[i][j]=(temp.a[i][j]+x.a[i][k]*y.a[k][j])%p;
return temp;
}
void calc(int n) //矩阵快速幂
{
while(n)
{
if(n&1) res=multiply(res,origin); //利用二进制的特点来计算
n>>=1;
origin=multiply(origin,origin);
}
}
int gcd(int big,int small){
int temp;
while (small!=0){
if(small>big) swap(big,small);
temp=big%small;
big=small;
small=temp;
}
return big;
}
int main(){
int T,n,m;
scanf("%d",&T);
while(T){
scanf("%d %d %d",&n,&m,&p);
init();
int s=gcd(n+2,m+2);
if(s>2) {calc(s-2); printf("%d\n",(res.a[0][0]+res.a[0][1])%p);}
else printf("1\n");
T--;
}
return 0;
}
/**************************************************************
Problem: 1202
Language: C++
Result: Accepted
Time:1 ms
Memory:1504 kb
****************************************************************/