当前位置: 代码迷 >> 综合 >> 51nod 1055 斐波拉契数列快速求解
  详细解决方案

51nod 1055 斐波拉契数列快速求解

热度:112   发布时间:2023-09-27 21:46:48.0

题目链接

看到n的数据量就知道不是简单递推了。

这里介绍俩种方法:

1. 求解数列的递推公式 

51nod 1055 斐波拉契数列快速求解

通过特征方程可以得到这个公式

但是发现这里既有浮点数也有除数,取膜的时候就不对了

a.对于除数,我们可以找到逆元,求出逆元即可

b.

对于浮点数sqrt(5),x=616991993是它的逆元,那么用这个数代替sqrt(5)即可

对于浮点数1/5 找到逆元是y=200000002

所以an = x*y*( (616991994/2)^n - (-616991992/2)^n)即可

2. 利用矩阵的性质(如下特点),

所以需要求fn的话,跑一下n次方的矩阵,然后返回矩阵的斜对角任意各一个值即可(他们相等)

#include<iostream>
using namespace std;
#define mod 1000000009
long long pow(long long n){long long ans[2][2] = {
   {1,0},{0,1}};long long a[2][2] ={
   {1,1},{1,0}};long long b[2][2] ={
   {1,1},{1,0}};while(n){if(n&1){for(int i = 0;i<2;i++)for(int j = 0;j<2;j++){b[i][j] = 0;for(int k = 0;k<2;k++)b[i][j] = (b[i][j] + ans[i][k]*a[k][j])%mod;}for(int i = 0;i<2;i++){for(int j = 0;j<2;j++)ans[i][j] = b[i][j]%mod;}}n>>=1;for(int i = 0;i<2;i++)for(int j = 0;j<2;j++){b[i][j] = 0;for(int k = 0;k<2;k++)b[i][j] = (b[i][j] + a[i][k]*a[k][j]%mod)%mod;}for(int i = 0;i<2;i++){for(int j = 0;j<2;j++)a[i][j] = b[i][j]%mod;}}return ans[1][0];
}
int main(){long long  n;cin>>n;cout<<pow(n);
}