斐波那契数列 矩阵快速幂

已知斐波那契数列 Fn=F​n−1​​+F​n−2​​ (n>=3),F1=1,F​2​=1求解该数列的第项结果对998244353取模。

提示:矩阵快速幂,unsigned long long的最大值:1844674407370955161(1.8e18)

输入格式:
输入一个正整数n (1<=n<=1e18)。

输出格式:
输出一个数,数列的第n项

输入样例1:
1
输出样例1:
1
输入样例2:
3
输出样例2:
2

分析

**
一 矩阵相乘
若A为n×k矩阵,B为k×m矩阵,则它们的乘积将是一个n×m矩阵。两个矩阵能相乘的前提条件为前一个矩阵的列数等于后一个矩阵的行数。
两矩阵相乘的代码如下

for(int i=0;i<n;i++)
{
     
	for(int j=0;j<m;j++)
	{
     
		c[i][j]=0;//赋初值 
		for(int z=0;z<k;z++)
			c[i][j]=c[i][j]+a[i][k]*b[k][j];
	}
}

二 快速幂
普通快速幂的方法为:求a^n,(n特别大的时候),用二分法
先看小一点的,A的9次方

A^9

= AAAAAAAAA 【一个一个乘,要乘9次】

= A*(AA)(AA)(AA)(A*A)

= A*(A2)4 【A平方后,再四次方,还要乘上剩下的一个A,要乘6次】

= A*((A2)2)^2【A平方后,再平方,再平方,还要乘上剩下的一个A,要乘4次】

所以如果n为100000000时,运用快速幂只需要乘log2^n。
代码如下

int res=1
while(n>0)
{
     
	if(n%2)
		res=res*a;
	a=a*a;
	n=n/2;
}
return res;

矩阵快速幂只需把res换成单位矩阵,a换成对应的矩阵即可。
下面上代码

struct Matrix
{
     
	unsigned long long M[2][2];
};//结构体 矩阵。

struct Matrix qul(unsigned long long t,struct Matrix a) 
{
     
	struct Matrix res;
	//单位矩阵 
	res.M[0][0]=1;res.M[0][1]=0;
	res.M[1][0]=0;res.M[1][1]=1;
	while(t>0)
	{
     
		if(t%2) res=mul(res,a);
		a=mul(a,a);
		t=t/2;
	}
	return res;
}

重点!!!!
斐波那契数列与矩阵的关系!!!
在这里插入图片描述
在这里插入图片描述
但要注意,若n>=3,即斐波那契数列是从f1开始的则上面的n-1要改为n-2。若从f0开始则为n-1
所以若求第n项,则求出上述矩阵的n次幂即可,然后将得到的新矩阵的第一行相加即为第n项的值

完整代码如下

#include
#include
#define Max 998244353


struct Matrix
{
     
	unsigned long long M[2][2];//数据类型要一致!!!!!我刚开始在pta上答案一直错误,就是因为把它定义成了int型数据,忽略了乘时数据会变大!!!!
};//结构体 矩阵。

struct Matrix mul(struct Matrix a,struct Matrix b)//矩阵相乘,返回值为矩阵 
{
     
	struct Matrix c;//创建新的矩阵来放矩阵相乘的结果 
	for(int i=0;i<2;i++)
	{
     
		for(int j=0;j<2;j++)
		{
     
			c.M[i][j]=0;//初始化新矩阵
			for(int k=0;k<2;k++)
			{
     
				c.M[i][j]=c.M[i][j]+a.M[i][k]*b.M[k][j];
				c.M[i][j]=c.M[i][j]%Max;//取模别忘了
			}
		}
	}
	return c;
 } 
//快速幂
struct Matrix qul(unsigned long long t,struct Matrix a) 
{
     
	struct Matrix res;
	//单位矩阵 
	res.M[0][0]=1;res.M[0][1]=0;
	res.M[1][0]=0;res.M[1][1]=1;
	while(t>0)
	{
     
		if(t%2) res=mul(res,a);
		a=mul(a,a);
		t=t/2;
	}
	return res;
}


int main()
{
     
	unsigned long long n,sum=0;
	scanf("%llu",&n);
	struct Matrix a;
    struct Matrix d;
	a.M[0][0]=1;
	a.M[0][1]=1;
	a.M[1][0]=1;
	a.M[1][1]=0;
	if(n==1||n==2) printf("1");
	else
	{
     
		d=qul(n-2,a);
		sum=(d.M[0][0]+d.M[0][1])%Max;
		printf("%llu",sum);
	}
		return 0;
}

**
注意:本题中n的值过大所以需要用到快速幂矩阵,切要对结果取模,否则会出错

你可能感兴趣的:(二分法,c语言,二分法,算法)