Problem
Source: Codeforces
Find the $n^th$ Fibonacci
number modulo $10^9+7$. So, you need to find $F_n$ in the sequence defined as
$$
\begin{aligned}
F_0 & = 0\\
F_1 & = 1\\
F_i & = F_{i-1} + F_{i-2} (i >= 2)
\end{aligned}
$$
Example:
Input: 50
Output: 586268941
Solution
Approach 1: Dynamic Programing
Using fibonacci’s difference equation as a recurrence relation, i can write to a program like this:
int f0 = 0, f1 = 1, fn;
for(int i = 2; i <= n; i++){
fn = f0 + f1;
f0 = f1;
f1 = fn;
}
return fn;
This code’s complexity is $O(n)$ which is fine with $n <= 5. 10^6$. However, $n$ is up to $10^{18}$ in this problem so i need a better way, must be at least $O(log^2 n)$ complexity.
Approach 2: Matrix exponentiation
I can rewrite its different equation as $$ \begin{aligned} F_{n+1} & = 1\ F_n + 1\ F_{n-1}\\ F_{n} & = 1\ F_n + 0\ F_{n-1}\\ \\ => \begin{bmatrix} F_{n+1} \\ F_n \end{bmatrix} & = \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} \begin{bmatrix} F_n \\ F_{n-1} \end{bmatrix} \\\\ & = \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}^n \begin{bmatrix} F_1 \\ F_0 \end{bmatrix} \end{aligned} $$ As you can see, F_n is equal to $2^{nd}$ row $\begin{bmatrix} 1 & 1 \\ 1 & 0\end{bmatrix}^n$ multiply by $\begin{bmatrix} F_1 \\ F_0 \end{bmatrix}$. Also, $F_1 = 1, F_0 = 0$ so $F_n$ is now a value at $2^{nd}$ row and $1^{st}$ column of $\begin{bmatrix} 1 & 1 \\ 1 & 0\end{bmatrix}^n$.
Large n power
I’ll calculate power with large $n$ by square the base and halve the exponent rather than multiply the base $n$ times as definition. For example, instead of calculate $2^6 = 2\times2\times2\times2\times2\times2,$ i’ll do $2^6 = 4^4 = 8^2$
In other words, i’ll try to replace multiplying a small many times to multiplying 2 or 3 times large numbers. By this, i can reduce the complexity to $O(logn)$
int res = 1;
while (b > 0){
if(b % 2)
res = res * a;
a = a * a;
b >>= 1
}
Now, the base is not a number but a $2 \times 2$ matrix so i need to declare a struct
, so does the funtions for calculating and storing:
const unsigned long long mod = 1e9 + 7;
struct matrix{
unsigned long long a, b, c, d;
};
matrix multiply(matrix A, matrix B){
matrix C;
C.a = (A.a*B.a + A.b*B.c) % mod;
C.b = (A.a*B.b + A.b*B.d) % mod;
C.c = (A.c*B.a + A.d*B.c) % mod;
C.d = (A.c*B.b + A.d*B.d) % mod;
return C;
}
matrix power(matrix a, long long b){
matrix res;
//res is an identity matrix
res.a = res.d = 1;
res.b = res.c = 0;
while (b > 0){
if(b % 2)
res = multiply(res, a);
a = multiply(a, a);
b >>= 1;
}
return res;
}
Finally, for $F = \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}$, the final result is power(F,n).c
.
Thank you for reading.