小白月赛20
斐波那契
题目大意:
输出前斐波那契数列前n项平方和,1<=n<=1e18。
前备知识:
快速幂和矩阵,可以进我的博客了解一下,小白非常容易理解:
思路:
斐波那契数列前n项平方和有递推式:前n项平方和等于 f[n] * f[n+1]。
因为n非常大,用递归的思路去求肯定超时,所以想办法用\thetaθ (log n)的方法去解,用矩阵转化为乘法,然后快速幂求解就可以了。
一道模板题,难度适宜。
Code:
(那个时候学的代码)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 1e9 + 7;
struct node
{
ll matrix[2][2];//结构体中的矩阵
node()//定义了结构体后会自动初始化
{
memset(matrix,0,sizeof(matrix));
}
void one()//单位矩阵
{
matrix[0][0]=1;
matrix[1][1]=1;
}
node operator*(node other)//定义了结构体后就会有这个性质 operator是是对*的重载
{
node ans;//记录乘积
for(int i=0; i<2; i++)
for(int j=0; j<2; j++)
for(int k=0; k<2; k++)
{
ans.matrix[i][j] += matrix[i][k]*other.matrix[k][j];
ans.matrix[i][j]%=mod-1;
}
return ans;
}
};
/*
* 相当于p1的一个成员函数
p1*p2相当于对象p1调用函数“operator*”,把对象p2作为一个参数传递给该函数,从而实现了两个对象的相乘。
*/
node power(node a,ll b)//快速幂求a的b次方
{
node res;
res.one();//单位矩阵
while(b)
{
if(b&1)//b为奇数时乘底数
res=res*a;
a=a*a;
b>>=1;//b向后移
}
return res;
}
int main()
{
node real;//取a[n-1]+a[n-2];
real.matrix[0][0]=1;
real.matrix[0][1]=0;
real.matrix[1][0]=1;
real.matrix[1][1]=0;
node temp;//取到a[2] a[1],并有a[n-1]+a[n-2]和保存a[n-1]的功能
temp.matrix[0][0]=1;
temp.matrix[0][1]=1;
temp.matrix[1][0]=1;
temp.matrix[1][1]=0;
ll n;
scanf("%lld",&n);
if(n==1)
printf("1\n");
else
{
node ans1 = power(temp,n-2)*real;//计算出a[n]
node ans2 = power(temp,n-1)*real;//计算出a[n+1]
printf("%lld\n",ans1.matrix[0][0]*ans2.matrix[0][0]%mod);
}
}