HDU1568 Fibonacci
题目大意:
对于每一个输入n(0<=n<=100000000),输出斐波那契数列第n项的前4个数字。
思路:
附:因为博主比较懒,本文章中几张公式的图片来自 以下博客;
PY:看到这道题,第一个想到的是这是一道入门OI的斐波那契数列第n项取模的水题,结果就顺手打了一个程序结果发现样例WA了,然后才发现是第n项的前4个数字。。
这是一道数学题!
首先,我们来推几个结论。
结论一:
记f(n)为fibonacci数列第n项的值,
那么f(n) = ,这是通项公式,这里不给出证明。 附:对于本题,当n = 0, f(0) = 0。
结论二:
对于正实数n,显然n = a * 10k ( a <= 10, k为整数) (即科学计数法)。
那么log10( n ) = log10( a * 10k ) = log10( a ) + k ,
因为,a <= 10, 所以,log10( a ) < 1,又因为k为整数,所以,log10( a ) 为 log10( a * 10k ) 的小数部分。
所以log10( a ) = log10( a * 10k ) - [ log10( a * 10k ) ] //[ ] 为向下取整
结论三:
因为10log10( a ) = a,所以 a 的前4位有效数字即为a * 10k的前4位。
有了以上三个结论,我们可以开始推式子了:
首先,为了简化运算,我们对通项公式取对数,可以得到:
观察这个式子,我们会发现当n比较大的时候,最后一项几乎就是0,因为只要结果的前4位,方便计算,我们暂时忽略这一项试试。
所以我们就得到了这个东西:。
对于log10( f(n) ),我们令log10( a ) = log10( f(n) ) - [log10( f(n) )],通过结论二,我们可以发现log10( a ) 就是 log10( (f(n) ) 的小数部分。
接下来, 我们运用结论三,令ans = 10log10( a ) ,如果精度足够高,那么ans =a,其实说白了就是利用小数的运算使答案的末尾数字直接失去精度而消失,留下答案的前几位。
这时候我们再回到结论二的开头,我们会发现 f(n) = ans * 10k,当然,精度不够,可是f(n)的前几位都在ans中保留下来了。
此时输出ans前4位有效数字就能够得到答案。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 using namespace std; 7 int ans[25]; 8 int i,n,m; 9 const double BASE1 = (1.0+sqrt(5.0))/2; 10 double num1,num2; 11 int main(){ 12 ans[0]=0; 13 ans[1]=ans[2]=1; 14 for(i=3;i<=21;i++){ 15 ans[i]=(ans[i-1]+ans[i-2]); 16 } 17 while(scanf("%d",&m)==1){ 18 if(m<=20){ 19 printf("%d\n",ans[m]); 20 }else{ 21 num1=m*log10(BASE1); num2=log10(1/sqrt(5)); 22 num1=num1+num2; 23 num1=num1-floor(num1); 24 num1=pow(10,num1); 25 while(num1<1000) num1*=10; 26 printf("%d\n",(int)num1); 27 } 28 } 29 return 0; 30 }