HDU 1568 斐波拉契数列(拓展)

HDU 1568

  1. 使用斐波拉契数列的递推式进行计算,而不是循环的计算出所要求的。这会超出时间限制。
    在这里插入图片描述

  2. 计算出来的结果可能会很大,应该使用double型存储。

  3. 如何求一个大数的前m位呢?思路应该是下面这个样子的:

当一个数非常大时,如何求出其前几位呢?

  • 如果是给定一个特定的数,当然可以逐步取出每一位即可。
  • 但是,当求 x y x^{y} 的前几位时怎么办呢?若x,y都非常大,则显然很难解决:也许可以用大数乘法,暴力求解,但我们明明只需要前几位,却全部进行运算,结果自然是既占内存,又耗时间。同理,对于此题——求斐波拉契数列的前几位来说,求出每个斐波拉契数显然是不合适的。因此,可以采用取对数的方法来解决。

取对数:

假设给出一个数x = 10234432,那么有:
log10(10234432) = log10(1.0234432 * 1 0 7 10^{7} ) = log10(1.0234432) + 7
由上式知:

  • 7log10(10234432)的整数部分;

  • log10(1.0234432)就是log10(10234432)的小数部分。

    • 可以算出log10(1.0234432) = 0.010063744,故 1 0 0.010063744 10^{0.010063744} = 1.023443198。
    • 所以,此时可以看出规律:要求该数的前4位,则将1.023443198 * 1000,即 1 0 0.010063744 10^{0.010063744} * 1000,即 1 0 l o g 10 ( 1.0234432 ) 10^{log10(1.0234432)} * 1000 —> pow(10, x取对数后的小数部分) * 1000
  1. 对上面的公式两边取对数:
    在这里插入图片描述
  2. 另外,需要提及的一点是前20项Fibonacci数需要自己计算,一方面是因为Fibonacci数未满4位,更重要的一点是Fibonacci数较小时,公式的精确度不高。比如第17项Fibonacci应该是1597,但公式求得的是1596;而19项Fibonacci应该是4181,但公式求得的是4180

AC代码:

#include<cstdio>
#include<iostream>  
#include<cmath>
using namespace std;
int f[21] = {0, 1}; //前20位都在四位数以内
int main()
{	
	//freopen("data.in", "r", stdin); 
	for (int i = 2; i < 21; i++)
		f[i] = f[i-1] + f[i-2];
		
	int n;
	while (cin >> n) //边输入边计算 
	{
		double res;
		if (n <= 20)
		{	
			cout << f[n] << endl;
		}
		else 
		{
			res = log10(1.0/sqrt(5.0))+n*log10((1+sqrt(5.0))/2);
			res = res - floor(res);
			res = pow(10.0, res);
			while (res < 1000)
				res *= 10;
			cout << (int)res << endl;
		}
	}	
	return 0;
}
发布了53 篇原创文章 · 获赞 33 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/jy_z11121/article/details/103097394