当我看到这题时,发现又是好大的数取前几位时,我懵了,真心不知道用什么方法做,不过上网搜搜别人大牛的解题报告,发现原来用log,发现原来log的作用这么大!
原理如下:
先看对数的性质,loga(b^c)=c*loga(b),loga(b*c)=loga(b)+loga(c);
假设给出一个数10234432,那么log10(10234432)=log10(1.0234432*10^7)=log10(1.0234432)+7;
log10(1.0234432)就是log10(10234432)的小数部分.
log10(1.0234432)=0.010063744
10^0.010063744=1.023443198
那么要取几位就很明显了吧~
先取对数(对10取),然后得到结果的小数部分bit,pow(10.0,bit)以后如果答案还是<1000那么就一直乘10。
注意偶先处理了0~20项是为了方便处理~
这题要利用到数列的公式:an=(1/√5) * [((1+√5)/2)^n-((1-√5)/2)^n](n=1,2,3.....)
取完对数
log10(an)=-0.5*log10(5.0)+((double)n)*log(f)/log(10.0)+log10(1-((1-√5)/(1+√5))^n)其中f=(sqrt(5.0)+1.0)/2.0;
log10(1-((1-√5)/(1+√5))^n)->0
所以可以写成log10(an)=-0.5*log10(5.0)+((double)n)*log(f)/log(10.0);
最后取其小数部分。
该段转自:http://hi.baidu.com/aekdycoin/item/a4407c37850e5b9db80c03a6
代码如下:
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int main()
{
int n,i;
int f[21]={0,1,1};
double k,p,sum;
for(i=3; i<=20; i++)f[i]=f[i-1]+f[i-2];
while(scanf("%d",&n)!=EOF)
{
if(n<=20)
{
cout<<f[n]<<endl;
continue;
}
k=(sqrt(5.0)+1.0)/2.0;
p=-0.5*log(5.0)/log(10.0)+(n*1.0)*log(k)/log(10.0);
p=p-floor(p);
sum=pow(10.0,p);
while(sum<1000)sum*=10.0;
printf("%d\n",(int)sum);
}
return 0;
}
上面为什么对前20不用这个呢?因为我们必须知道斐波纳契数的前20个数位数都是小于5位数!
有了这个就很方便了!
其中还用到了floor 函数!