A Lagged Fibonacci Sequence
Define the sequence: g(k) = 1 for 0 <= k <= 1999, g(k) = g(k-2000) + g(k-1999) for k >= 2000. Find g(10^18) mod 20092010.
Problem Statement
This archive keeps the full statement, math, and original media on the page.
A sequence is defined as:
-
\(g_k = 1\), for \(0 \le k \le 1999\)
-
\(g_k = g_{k-2000} + g_{k - 1999}\), for \(k \ge 2000\).
Find \(g_k \bmod 20092010\) for \(k = 10^{18}\).
Problem 258: A Lagged Fibonacci Sequence
Mathematical Foundation
Theorem 1 (Characteristic Polynomial). The linear recurrence has characteristic polynomial
Proof. Substituting the ansatz into the recurrence:
Theorem 2 (Reduction to Polynomial Arithmetic). Let be the companion matrix of the recurrence. By the Cayley—Hamilton theorem, . Therefore, computing reduces to computing in the polynomial ring , where .
Proof. The state vector satisfies , so . By Cayley—Hamilton, , so any polynomial in can be reduced modulo . In particular, is determined by .
Lemma 1 (Sparse Reduction). The reduction is extremely efficient: for a polynomial of degree , each term is replaced by , requiring only 2 additions per excess degree.
Proof. From in the quotient ring, we get . Applying this rule iteratively from the highest-degree term downward reduces any polynomial to degree . Each application involves exactly 2 coefficient additions.
Theorem 3 (Extraction of ). If in , then
since all initial values are for .
Proof. The general term of the recurrence is a linear combination of initial values: where the coefficients are determined by . The polynomial encodes exactly these coefficients (this follows from the isomorphism between the polynomial quotient ring and the matrix algebra generated by ). With for all , the sum simplifies.
Editorial
g(k) = g(k-2000) + g(k-1999) for k >= 2000 g(k) = 1 for 0 <= k <= 1999 Find g(10^18) mod 20092010. Characteristic polynomial: p(x) = x^2000 - x - 1 So x^2000 ≡ x + 1 (mod p(x)) Compute x^(10^18) mod p(x) in Z_m[x], then g(10^18) = sum of coefficients (since all g(i) = 1 for i < 2000). We compute x^K mod p(x) in Z_m[x], where p(x) = x^2000 - x - 1. We then multiply polynomials A, B (each degree < 2000). Finally, result C has degree < 4000.
Pseudocode
K = 10^18, m = 20092010
Compute x^K mod p(x) in Z_m[x], where p(x) = x^2000 - x - 1
Multiply polynomials A, B (each degree < 2000)
Result C has degree < 4000
Reduce C modulo p(x): for d = deg(C) down to 2000:
C[d-1999] += C[d]
C[d-2000] += C[d]
C[d] = 0
All operations mod m
Binary exponentiation
if K is odd
Extract answer: sum of coefficients
Complexity Analysis
- Time: Binary exponentiation performs polynomial multiplications. Each multiplication of two degree- polynomials costs (or with FFT) for the convolution, plus for sparse reduction. Total: . With and : approximately operations.
- Space: for storing the polynomial coefficients ().
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
/*
* Problem 258: A Lagged Fibonacci Sequence
*
* g(k) = g(k-2000) + g(k-1999) for k >= 2000
* g(k) = 1 for 0 <= k <= 1999
*
* Find g(10^18) mod 20092010.
*
* Characteristic polynomial: x^2000 - x - 1 = 0
* So x^2000 ≡ x + 1 (mod p(x))
*
* We compute x^(10^18) mod p(x) in Z_m[x], then:
* g(10^18) = sum of coefficients a_i * g(i) = sum of a_i (since g(i)=1 for i<2000)
*
* Answer: 12747994
*/
const int N = 2000;
const long long MOD = 20092010;
typedef vector<long long> Poly;
// Reduce polynomial modulo p(x) = x^2000 - x - 1
// i.e., x^2000 ≡ x + 1
void reduce(Poly& a) {
while ((int)a.size() > N) {
long long coeff = a.back();
int deg = a.size() - 1;
a.pop_back();
// x^deg = coeff * x^(deg-2000) * x^2000 = coeff * x^(deg-2000) * (x + 1)
// = coeff * (x^(deg-1999) + x^(deg-2000))
int base = deg - N;
a[base] = (a[base] + coeff) % MOD;
a[base + 1] = (a[base + 1] + coeff) % MOD;
}
}
// Multiply two polynomials mod p(x) mod MOD
Poly polymul(const Poly& a, const Poly& b) {
int sa = a.size(), sb = b.size();
Poly c(sa + sb - 1, 0);
for (int i = 0; i < sa; i++) {
if (a[i] == 0) continue;
for (int j = 0; j < sb; j++) {
c[i + j] = (c[i + j] + a[i] * b[j]) % MOD;
}
}
reduce(c);
return c;
}
int main() {
// Compute x^(10^18) mod p(x) mod 20092010
long long exp = 1000000000000000000LL;
// result = 1 (the polynomial "1")
Poly result(1, 1);
// base = x
Poly base(2, 0);
base[1] = 1;
while (exp > 0) {
if (exp & 1) {
result = polymul(result, base);
}
base = polymul(base, base);
exp >>= 1;
}
// g(10^18) = sum of a_i * g(i) where g(i) = 1 for 0 <= i <= 1999
long long ans = 0;
for (int i = 0; i < (int)result.size(); i++) {
ans = (ans + result[i]) % MOD;
}
cout << ans << endl;
return 0;
}
"""
Problem 258: A Lagged Fibonacci Sequence
g(k) = g(k-2000) + g(k-1999) for k >= 2000
g(k) = 1 for 0 <= k <= 1999
Find g(10^18) mod 20092010.
Characteristic polynomial: p(x) = x^2000 - x - 1
So x^2000 ≡ x + 1 (mod p(x))
Compute x^(10^18) mod p(x) in Z_m[x], then
g(10^18) = sum of coefficients (since all g(i) = 1 for i < 2000).
Answer: 12747994
"""
N = 2000
MOD = 20092010
def reduce_poly(a):
"""Reduce polynomial modulo p(x) = x^2000 - x - 1.
Uses: x^2000 ≡ x + 1 (mod p(x))."""
while len(a) > N:
coeff = a.pop()
deg = len(a) # after pop, this is the original degree
base = deg - N
a[base] = (a[base] + coeff) % MOD
a[base + 1] = (a[base + 1] + coeff) % MOD
return a
def poly_mul(a, b):
"""Multiply two polynomials mod p(x) mod MOD."""
sa, sb = len(a), len(b)
c = [0] * (sa + sb - 1)
for i in range(sa):
if a[i] == 0:
continue
ai = a[i]
for j in range(sb):
c[i + j] = (c[i + j] + ai * b[j]) % MOD
return reduce_poly(c)
def poly_pow(exp_val):
"""Compute x^exp_val mod p(x) mod MOD using binary exponentiation."""
result = [1]
base = [0, 1]
while exp_val > 0:
if exp_val & 1:
result = poly_mul(result, base)
base = poly_mul(base, base)
exp_val >>= 1
return result
def main():
exp_val = 10**18
result = poly_pow(exp_val)
# g(10^18) = sum of coefficients a_i * g(i), and g(i) = 1 for all i < 2000
ans = sum(result) % MOD
print(ans)
if __name__ == "__main__":
main()