简介: 如果斐波那契数小于8位的就输出这个数,大于8位的就输出前四位,以及后四位
公式部分:
Fibonacci求和公式:
F
(
n
)
=
1
5
[
(
1
+
5
2
)
n
−
(
1
−
5
2
)
n
]
(
a
0
=
0
,
a
1
=
1
)
\begin{aligned}F\left( n\right)=\dfrac {1}{\sqrt {5}}\left[ \left( \dfrac {1+\sqrt {5}}{2}\right) ^{n}-\left( \dfrac {1-\sqrt {5}}{2}\right) ^{n}\right] \\ \left( a_{0}=0,a_{1}=1\right) \end{aligned}
F(n)=51[(21+5)n−(21−5)n](a0=0,a1=1)
我们将两边取对数,其中当n够大时,以下式子无限接近于0,所以可以省略:
lim
n
>
40
lg
(
1
−
5
2
)
n
→
0
\lim _{n>40}\lg\left( \dfrac {1-\sqrt {5}}{2}\right) ^{n}\rightarrow 0
n>40limlg(21−5)n→0
最终得到如下公式
l
g
F
(
n
)
=
x
+
n
y
(
x
=
lg
1
5
,
y
=
lg
1
+
5
2
)
\begin{aligned}lgF\left( n\right) =x+ny\\ \left( x=\lg \dfrac {1}{\sqrt {5}},y=\lg \dfrac {1+\sqrt {5}}{2}\right) \end{aligned}
lgF(n)=x+ny(x=lg51,y=lg21+5)
我们用这个公式解决当n>=40时数列前四位的问题
题目分析:
- 通过打表可以发现到39位为止都不超过8位数,当n>39时再分别求前四位和后四位
- 后四位矩阵快速幂求解
- 设 l g F ( n ) = a lgF\left( n\right)=a lgF(n)=a,当我们求出a时,只需要通过 a = a − ⌊ a ⌋ a=a-\lfloor a\rfloor a=a−⌊a⌋求出a的小数部分,之后 1 0 a × 1 e 3 10^{a}\times 1e3 10a×1e3即可得到 F ( n ) F\left( n\right) F(n)的前四位(整数部分只是贡献结果末尾的0罢了)
代码:
#include<stdio.h>
#include<math.h>
#include<string.h>
#define LL long long
#define fo(i,a,b) for(int i=a;i<b;i++)
int fib[40] = {0, 1};
const double x = log10(1.0 / sqrt(5.0));
const double y = log10((1.0 + sqrt(5.0)) / 2.0);
const int M=1e4;
struct mat{
LL a[2][2];
mat operator*(mat t){
mat r; memset(r.a,0,sizeof(r.a));
fo(i,0,2)fo(k,0,2)fo(j,0,2)
r.a[i][j]=(r.a[i][j] +1ll*a[i][k]*t.a[k][j])%M;
return r;
}//重载矩阵乘法
}o,t;
void init(){
t.a[0][0] = t.a[1][1] = 1; t.a[0][1] = t.a[1][0] = 0;//别忘记清零
o.a[0][0] = o.a[1][0] = o.a[0][1] = 1; o.a[1][1] = 0;//别忘记清零
}
int main(){
int n,i,b;
double a;
for(i = 2; i < 40; ++i) fib[i] = fib[i-1] + fib[i-2];
while(scanf("%d",&n)==1){
init();
if(n < 40) printf("%d\n", fib[n]);
else{
a=x+n*y;
a-=(int)a;//整数部分最后是一堆0,丢掉即可
a=pow(10,a);
for (LL i=n;i;i>>=1,o=o*o)if(i&1)t=t*o;//快速幂
printf("%d...%0.4d\n", (int)(a*1000),t.a[0][1]%M);
}
}
return 0;
}