我该怎么做才能改进我的斐波纳契数发生器?

时间:2011-02-02 12:52:42

标签: c++ fibonacci

我正在解决这个问题:

G(n) is defined as

G(n) = G(n-1) + f(4n-1) , for n > 0

and G(0) = 0

f(i) is ith Fibonacci number. Given n you need to evaluate G(n)
     

modulo 1000000007。

Input

First line contains number of test cases t (t<40000). Each of the next t
     

行包含整数n(0 <= n <0。   2 ^ 51)。

Output

For each test case print G(n) modulo 1000000007.

Example

Input:
2
2
4



Output:


15
714

这是我写的代码:

typedef long long type;
#define check 1000000007
type x;
type y;

type f(type n)
{
    return(ceil((pow(1.618,n) - pow(-0.618,n))/((sqrt(5)*1.0))));
}
type val(type n)
{
    if(n==0)
    return 0;
    else 
    return (val(n-1)+f(4*n-1));
}
int main()
{
    cin>>x;
    while(x--)
    {
       cin>>y;
       cout<<val(y)%check<<endl;
       }
    //getch();
    return 0;
}

你能建议任何改进吗?

4 个答案:

答案 0 :(得分:1)

有时这些问题可以通过数学技巧解决,
而不是暴力解决方案。

在我看来,n和模数的大值表明了 存在一个聪明的解决方案。当然,找出解决方案是困难的部分。

(我不确定这在你的情况下是否理想,我只是指向你另一种方式)

例如,在Art of Computer Programming, Volume 1: Fundamental Algorithms中 Knuth使用“生成函数”,这是一种构造封闭形式的聪明方法 对于Fn斐波纳契数。

有关详细信息,请参阅Generating Functions (pdf)

  

为什么要关心   生成序列的函数?   有几个答案,但现在是   一:如果我们能找到一个产生   一个序列的功能,然后我们可以   经常为第n个发现一个封闭的形式   系数 - 这可能很漂亮   有用!例如,一个封闭的表格   x n 的系数   x /(1-x-x 2 )的幂级数   将是一个明确的公式   第n个斐波纳契数。 [...]

答案 1 :(得分:1)

G(n)= G(n-1)+ f(4n-1)= G(n-2)+ f(4n-1)+ f(4n-5)等。

因此

G(n)= f(4n-1)+ f(4n-5)+ f(4n-9)... f(3)

f(n)= f(n-1)+ f(n-2)= 2f(n-2)+ f(n-3)= 3f(n-3)+ 2f(n-4)= 5f(n-4)+ 3f(n-5) f(n-5)= 3f(n-8)+ 2f(n-9) 从而 f(n)= 5f(n-4)+ 9f(n-8)+ 6f(n-9) = 5f(n-4)+ 9f(n-8)+ 18f(n-12)+ 12f(n-13)

= 5f(n-4)+ 9f(n-8)+ 18f(n-12)+ 36f(n-16)+ 24f(n-17)

在任何情况下都清楚系数每次都会加倍。当然,从上面我们可以用f(n-8)等来定义f(n-4)。不确定这将导致什么。

这里有一个系列,f(3)= 2和f(2)= 1所以最后你会加上常数。

实际上,为了您的目的,您可以在一次通过中计算f(n),而不必在此时存储超过2个,并且当您通过计算f(n)时,您知道上面G的公式当n与每个点的3 mod 4一致时,你可以适当地更新G总和斐波那契数。

你找不到用这么大的数字(2到51的幂)保存一个表的空间,甚至不是磁盘,尽管它实际上是你需要存储在表中的总和(f(3), f(3)+ f(7),f(3)+ f(7)+ f(11)等)如果你要保存任何东西。

答案 2 :(得分:0)

所以f()是斐波那契函数?我建议你使用常规的递归算法。但是你可以通过添加缓存来显着提高性能,因为对于较小的i值的调用会经常重复调用f(i)。

您可以使用静态局部整数数组来完成此操作。如果元素为0则为未命中,因此您计算该值并将其存储在数组中。

这样你就可以避免使用浮点运算而不会填满堆栈。

答案 3 :(得分:0)

我认为获得G(n)价值的更好方法是计算它:

type val(type n, std::vector<type> &fib)
{
  type ret = 0, s = min(type(fib.size()), n);
  for(type i=0; i < s; ++i)
      ret += fib[i];

  if(n > fib.size()){    
    fib.reserve(n);
    int tmp;
    for(type i = fib.size(); i < n; ++i){
      tmp = f(4*i+3);
      fib.push_back(tmp);
      ret += tmp;
    }

  }
  return ret;
}

(对于整个代码检查http://www.ideone.com/jorMy

避免在任何地方递归,这样它就不会计算每次斐波那契函数。

编辑:我花了很多时间才发现(我的数学有点生锈),但你也可以这样写val:

numtype val(numtype n) {
  return ceil(2.218*pow(6.8541,n-1) - 0.018*pow(0.145898,n-1) - 0.2);
}

http://www.ideone.com/H1SYz上的代码)

这是您的总和的封闭形式。如果你想亲自找到它(毕竟是作业),请跟随Nick D回答。