欧拉项目#2(偶数斐波那契数):O(1) 解决方案

Haz*_*ziq 1 c algorithm math numbers fibonacci

欧拉计划 #2 偶数斐波那契数

斐波那契数列中的每一项新项都是通过添加前两项而生成的。从 1 和 2 开始,前 10 项将是:

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ... 通过考虑斐波那契数列中值不超过四百万的项,求偶数项的总和。

问题:是否可以在常数时间内解决这个问题?

Haz*_*ziq 5

这是 PE-2 的手动O(1)- ish解决方案,请参阅上面 @harold :( 的评论。我的解决方案是伪数学的,并不严格,但是嘿,它有效!

\n
\n

斐波那契数列中的每一项新项都是通过添加前两项而生成的。从 1 和 2 开始,前 10 项将是:

\n

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ... 通过考虑\n斐波那契数列中值不超过四百万的项,求\n偶数项的总和。

\n
\n

一些构建块:

\n
    \n
  • Binet 公式使我们能够立即计算F n
  • \n
  • 对于前n 个斐波那契数的和,还有另一个众所周知的公式,即F 0 + F 1 + ... + F n = F n+2 - 1
  • \n
  • 我们需要一个公式来计算斐波那契数列的前k 个偶数之和。E n表示序列中的第 n 个偶数,因此E 1 = 2。众所周知,E n = 4E n-1 - E n-2。这个问题的许多解决方案都利用了这个公式。做一些数学计算(附录中的证明),你可以看到
  • \n
\n

E 1 + E 2 + ... + E k = (E k+2 - 3E k+1 - 2) \xc3\xb7 4 = (F 3(k+2) - 3F 3(k+1) - 2 ) \ xc3\xb7 4因为En = F 3n

\n
    \n
  • 我们可以使用比奈公式计算以上内容。剩下的唯一问题是给定一个界限X k应该是多少?我们反转比奈公式来求解n,我们得到在此输入图像描述
  • \n
\n

而不是上限,我们取底以获得低于X 的斐波那契数的索引n。那么我们只需计算{F 0 , ..., F n }中有多少个偶数,并使用第3点的公式即可。

\n

C 实施:

\n

我用暴力解决方案对其进行了测试。似乎工作正常。

\n
#include <stdio.h>\n\n#include <math.h>\n\n// Input N\n// Output N\'th term of fibonacci\nunsigned long long binet(int N)\n{\n    long double phi = (1.0 + sqrt(5)) / 2.0;\n\n    return floor((pow(phi, N) / sqrt(5)) + 0.5);\n}\n\nint find_fib_n(unsigned long long F_n)\n{\n    return round(log(sqrt(5) * F_n) / log((1.0 + sqrt(5)) / 2.0));\n}\n\n// Input N\n// Count of even numbers in the first N fib nums\nint count_even_in_fib_seq(int N)\n{\n    if (N <= 3)\n        return 0;\n\n    int tmp = N;\n\n    tmp -= 4;\n\n    return 1 + floor(tmp / 3);\n}\n\n#define bound 4000000\n\nint main(void)\n{\n    int fib_approx_index = find_fib_n(bound);\n\n    printf("%d %llu %d\\n", fib_approx_index, binet(fib_approx_index), bound);\n\n    // Number of even numbers below bound\n    int K = count_even_in_fib_seq(fib_approx_index + 1);\n\n    printf("count %d\\n", K);\n\n    unsigned long long result = (-3 * binet(3 * (K + 1)) + binet(3 * (K + 2)) - 2) / 4;\n    printf("%llu", result);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

附录:前k个偶数斐波那契数之和的公式

\n

证明

\n

在网上浏览了一段时间后,我发现其他一些人也提出了类似的解决方案。查看这些链接以获取更多信息:

\n\n

谢谢阅读

\n

  • `return 1 + Floor(tmp / 3)` 不必要地采用 `int` 商,转换为 `double`,调用 `floor()`,然后将 `double` 转换回 `int`。使用“return 1 + tmp / 3”更简单。 (2认同)