HAUT 1286: czl的复仇计划【fib公式演变】

1286: czl的复仇计划

时间限制: 1 秒   内存限制: 128 MB
提交: 107   解决: 20
提交  状态 
题目描述

还记得上次czl给ykc做苦力的事情了吗,czl越想越气,于是决定报复一下ykc,可他知道ykc是不会轻易上当的,呢该怎么办呢,咦……有了,“嗨,ykc,我最近爱上了编程,可是遇到了一个难题,想了一晚上都没有任何思路,是关于斐波那契的,能请教一下你吗?”,“啊,斐波那契呀,呢不是so easy嘛。”ykc自信的说道,czl内心已经开始窃喜了,“既然你这么自信,呢要是你不能帮我解决,就要给我买好吃的,我可想吃肉了。”czl咽了一下口水。“当然可以了,怎么可能有我解决不了的斐波那契”ykc不屑的说道,ykc果然上当了。。。。。czl面无表情的说道:“呢道题是这样描述的,给你一个整数n,让你求斐波那契数列的第n项的前5位和后5位。”“哈哈,看来你是吃不上肉了,递推一下,求一求啦。”ykc仍然自信的说道。“等等,我还没说完呢,n有100000000这么大”,czl补充道。“啊。。。。哦”,ykc感觉到自己被坑了,可是来不及了,眼看就要月底了,ykc早就没钱了,聪明的你能帮帮他吗?
(注意:假如该项的斐波那契数列总位数小于等于10位,呢就直接输出就好了,否则按照 前5位***后5位  的格式输出)。

以上全是扯淡,只用求前5位就好了(毕竟czl也不想刁难ykc)

输入
多组测试实例,每行一个整数n(n<=100000000)
输出
要求输出的第n项
样例输入
0
1
2
3
4
5
35
36
37
38
39
40
64
65
样例输出
0
1
1
2
3
5
92274
14930
24157
39088
63245
10233
10610
17167
思路:(标程)

首先回顾一下对数的性质: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,
要求该数的前4位,则将1.023443198*1000即可,因此,pow(10.0,x的小数部分)即可方便求出x的前几位。

参考代码:
[cpp] view plain copy
  1. int  main(void)  
  2. {  
  3.     double x,tmp;  
  4.     while(scanf("%lf",&x)!=EOF)  
  5.     {  
  6.         tmp=log(x)/log(10.0);  
  7.         tmp=tmp-floor(tmp);  
  8.         tmp=pow(10.0,tmp);  
  9.         while(tmp<1000)  
  10.             tmp*=10;  
  11.         printf("%d\n",(int)tmp);  
  12.     }  
  13.     return 0;  
  14. }  
然而本题要求的第n项斐波那契数列的话,要用到斐波那契数列的通项公式



取完对数


又因为当n很大时,log10(1-((1-√5)/(1+√5))^n)->0

故原始可化为log10(an)=-0.5*log10(5.0)+((double)n)*log(f)/log(10.0); 最后取小数部分即可

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
LL f[30];

int main() {
	f[0] = 0;
	f[1] = f[2] = 1;
	for(int i = 3; i <= 25; i++) {
		f[i] = f[i - 1] + f[i - 2];
	//	printf("%d\n", f[i]); 第25位正好是最后一个五位数 
	}
	LL n;
	while(scanf("%lld", &n) != EOF) {
		if(n <= 25) {
			printf("%lld\n", f[n]);
			continue;
		}
		double x, y, z;
		x = -0.5 * log(5.0) / log(10.0);
		y = x + double(n) * log((1.0 + sqrt(5.0)) / 2.0) / log(10.0);
		y -= floor(y);
		z = pow(10.0, y);
		while(z < 10000) {
			z *= 10.0;
		}
		printf("%05lld\n", (LL)z);
	} 
	return 0;
} 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值