Fibonacci problem again#1250

Fibonacci problem again (Editorial)

Theorem. For the Fibonacci numbers, the following formula holds:

S(n) = F(0) + F(1) + ... + F(n) = F(n + 2) - 1

Proof. We prove the statement by induction.

F(0) = F(2) - 1,

That is, 0 = 1 - 1, which is true.

S(n) = F(n + 2) - 1

Then:

S(n + 1) = F(0) + F(1) + ... + F(n) + F(n + 1) = \\ (F(n + 2) - 1) + F(n + 1) = F(n + 3) - 1,

which completes the proof

Then the desired sum

S = F(a) + F(a + 1) + ... + F(b)

can be computed as

S = S(b) - S(a - 1)

Computing Fibonacci numbers using Binet's formula

Consider the generating function for the Fibonacci numbers (F_0 = 0, F_1 = 1):

G(x) = \sum_{n = 0}^∞ F_n x^n = F_0 + F_1x + \sum_{n = 2}^∞ F_n x^n = \\ F_0 + F_1x + \sum_{n = 2}^∞ (F_{n - 1} + F_{n - 2}) x^n = \\ x + \sum_{n = 2}^∞ F_{n - 1} x^n + \sum_{n = 2}^∞ F_{n - 2} x^n = \\ x + x \sum_{n = 1}^∞ F_n x^n + x^2 \sum_{n = 0}^∞ F_n x^n = \\ x + xG(x) + x^2G(x)

From this it follows that:

G(x) (1 - x - x^2) = x, \\ G(x) = \frac{x}{1 - x - x^2}

Let us decompose the generating function into partial fractions. First, find the roots of the denominator:

1 - x - x^2 = (1 - φx) (1 - ψx),

where

φ = \frac{1 + \sqrt{5}}{2}, ψ = \frac{1 - \sqrt{5}}{2}

Now represent the generating function as:

\frac{x}{1 - x - x^2} = \frac{A}{1 - φx} + \frac{B}{1 - ψx}

Solving the system, we obtain:

A = \frac{1}{\sqrt{5}}, B = -\frac{1}{\sqrt{5}}

Taking into account that

\frac{1}{1 - rx} = \sum_{n = 0}^∞ r^n x^n,

the generating function can be rewritten as:

G(x) = \frac{1}{\sqrt{5}} \left( \frac{1}{1 - φx} + \frac{1}{1 - ψx} \right) = \frac{1}{\sqrt{5}} \sum_{n = 0}^∞ (φ^n - ψ^n) x^n

But since

G(x) = \sum_{n = 0}^∞ F_n x^n

equating the coefficients of x^n gives:

F_n = \frac{φ^n - ψ^n}{\sqrt{5}} = \frac{1}{\sqrt{5}} \left( \left( \frac{1 + \sqrt{5}}{2} \right)^n - \left( \frac{1 - \sqrt{5}}{2} \right)^n \right) = \frac{(1 + \sqrt{5})^n - (1 - \sqrt{5})^n}{2^n \sqrt{5}}

Computing Fibonacci Numbers Using an Identity

For the Fibonacci numbers, the following identity is known:

F_{n + m} = F_m \cdot F_{n+1} + F_{m - 1} \cdot F_n

From it, the following special cases follow directly:

These formulas make it possible to compute Fibonacci numbers using a divide-and-conquer approach, reducing the computation of F_n to values with indices approximately half as large.

The base cases are handled separately:

F_0 = 0, F_1 = F_2 = 1

With this approach, the recursion depth is proportional to log_2n, and the time complexity of the algorithm is O(log_2n).

Example

Let us compute some Fibonacci numbers using Binet’s formula, working in the extended field Z_p (\sqrt{5}) with a large modulus .

F_2 = \frac{1}{\sqrt{5}} \left( \left( \frac{1 + \sqrt{5}}{2} \right)^2 - \left( \frac{1 - \sqrt{5}}{2} \right)^2 \right) = \frac{(1 + \sqrt{5})^2 - (1 - \sqrt{5})^2}{2^2 \sqrt{5}} = \frac{(6 + 2\sqrt{5}) - (6 - 2\sqrt{5})}{2^2 \sqrt{5}} = \frac{4\sqrt{5}}{4\sqrt{5}} = 1 \\ F_3 = \frac{1}{\sqrt{5}} \left( \left( \frac{1 + \sqrt{5}}{2} \right)^3 - \left( \frac{1 - \sqrt{5}}{2} \right)^3 \right) = \frac{(1 + \sqrt{5})^3 - (1 - \sqrt{5})^3}{2^3 \sqrt{5}} = \frac{(16 + 8\sqrt{5}) - (16 - 8\sqrt{5})}{2^3 \sqrt{5}} = \frac{16\sqrt{5}}{8\sqrt{5}} = 2 \\ F_4 = \frac{1}{\sqrt{5}} \left( \left( \frac{1 + \sqrt{5}}{2} \right)^4 - \left( \frac{1 - \sqrt{5}}{2} \right)^4 \right) = \frac{(6 + 2\sqrt{5})^2 - (6 - 2\sqrt{5})^2}{2^4 \sqrt{5}} = \frac{(56 + 24\sqrt{5}) - (56 - 24\sqrt{5})}{2^4 \sqrt{5}} = \frac{48\sqrt{5}}{16\sqrt{5}} = 3

Let us illustrate the application of the formulas with an example:

F_6 = F_3 \cdot F_4 + F_2 \cdot F_3 = 2 \cdot 3 + 1 \cdot 2 = 6 + 2 = 8, \\ F_7 = F_4^2 + F_3^2 = 3^2 + 2^2 = 9 + 4 = 13

Algorithm implementation

Declare the constant , which will be used as the modulus for all computations.

#define MOD 1000000007

Declare a variable of type to store (memoize) already computed Fibonacci numbers.

map<long long, long long> fib;

The function f computes the -th Fibonacci number modulo .

long long f(long long n)
{
  if (n == 0) return 0;
  if (n == 1) return 1;
  if (n == 2) return 1;

If the -th Fibonacci number has already been computed and stored in , it is returned immediately without recomputation.

  if (fib[n]) return fib[n];

Next, we decompose the number as follows:

  long long k = n / 2;

Store the result and return it.

  if (n % 2 == 1) // n = 2*k + 1
    return fib[n] = (f(k) * f(k) + f(k + 1) * f(k + 1)) % MOD;
  else // n = 2*k
    return fib[n] = (f(k) * f(k + 1) + f(k - 1) * f(k)) % MOD;
}

The main part of the program. For each test case, read the input data and print the answer.

while (scanf("%lld %lld", &a, &b) == 2)
  printf("%lld\n", (f(b + 2) - f(a + 1) + MOD) % MOD);

Algorithm implementation – Binet's formula

Declare the constant , which will be used as the modulus for all computations.

#define MOD 1000000007

Declare the structure to store a number of the form x + y \sqrt{5}.

struct Num
{
  long long x, y; // x + y*sqrt(c)
  Num(long long x_ = 0, long long y_ = 0) : x(x_), y(y_) {}
};

Implement multiplication in the field Z_p (\sqrt{5}). The function mult returns the product of the numbers and .

Num mult(Num& a, Num& b)
{
  Num res;
  res.x = (a.x * b.x + 5 * a.y % MOD * b.y) % MOD;
   res.y = (a.x * b.y + a.y * b.x) % MOD;
   return res;
}

The function pow performs exponentiation of base^n, where is a number in the field Z_p (\sqrt{5}).

Num pow(Num base, long long n)
{
  Num res = { 1, 0 }; // единица поля
  while (n > 0)
  {
    if (n & 1)
      res = mult(res, base);
    base = mult(base, base);
    n >>= 1;
  }
  return res;
}

The function modpow computes the value of a^k~mod~p.

long long pow(long long x, long long n)
{
  long long res = 1;
  x %= MOD;
  while (n > 0)
  {
    if (n & 1) res = res * x % MOD;
    x = x * x % MOD;
    n >>= 1;
  }
  return res;
}

The function fib computes the -th Fibonacci number.

long long fib(long long n)
{

Initialize the constants φ = 1 + \sqrt{5} and ψ = 1 - \sqrt{5}.

  Num phi(1, 1);
  Num psi(1, MOD - 1);

Compute the powers A = φ^n and B = ψ^n.

  Num A = pow(phi, n);
  Num B = pow(psi, n);

Since

F_n = \frac{1}{\sqrt{5}} \left( \left( \frac{1 + \sqrt{5}}{2} \right)^n - \left( \frac{1 - \sqrt{5}}{2} \right)^n \right) = \frac{(1 + \sqrt{5})^n - (1 - \sqrt{5})^n}{2^n \sqrt{5}} = \frac{(A_x + A_y \sqrt{5}) - (B_x + B_y \sqrt{5})}{2^n \sqrt{5}},

compute the numerator and denominator separately.

Note that A_x = B_x (so A_x - B_x = 0), and the coefficient of \sqrt{5} in the numerator is A_y - B_y.

  long long numerator = (A.y - B.y + MOD) % MOD;

Compute 2^n in the denominator.

  long long denom = pow(2, n);

Both the numerator and the denominator contain a factor of \sqrt{5}. Cancel this factor, leaving the result to be computed as:

(A_y - B_y) \cdot (2^n)^{-1} = numerator \cdot denom^{-1}
  long long denom_inv = pow(denom, MOD - 2);
  return numerator * denom_inv % MOD;
}

The main part of the program. For each test case, read the input data and print the answer.

while (scanf("%lld %lld", &a, &b) == 2)
  printf("%lld\n", (fib(b + 2) - fib(a + 1) + MOD) % MOD);