UVa 10229: Modular Fibonacci | MathBlog
e are given two integers, and . We are then asked to calculate and output the th Fibonacci number, modulo .
As you can see, can be pretty big. Let's have a look at a few different methods to compute the th Fibonacci number.
https://github.com/sfmunera/uva/blob/master/UVa10229_ModularFibonacci.java
https://f0rth3r3c0rd.wordpress.com/2011/10/19/uva-10229-modular-fibonacci/
Read full article from UVa 10229: Modular Fibonacci | MathBlog
e are given two integers, and . We are then asked to calculate and output the th Fibonacci number, modulo .
As you can see, can be pretty big. Let's have a look at a few different methods to compute the th Fibonacci number.
The Fibonacci numbers have the following matrix identity:
Now if we put the first Fibonacci numbers into the right-most matrix, and instead of multiplying it once with the other matrix, we multiply it times, we get:
Or equivalently:
public
static
int
pow(
int
x,
int
n) {
// our base case: x^0 = 1
if
(n ==
0
)
return
1
;
// if n is odd
if
(n %
2
!=
0
)
return
x * pow(x, n -
1
);
// if n is even, calculate x^(n / 2)
int
sqrt = pow(x, n /
2
);
// and return it squared
return
sqrt * sqrt;
}
// raise the matrix to the n-th power
public
Matrix pow(
int
n) {
if
(n ==
0
) {
// if n is 0, we return the identity matrix
Matrix res =
new
Matrix(getRows(), getCols());
for
(
int
i =
0
; i < getRows() && i < getCols(); i++)
res.set(i, i,
1
);
return
res;
}
else
if
(n %
2
==
0
) {
// if n is even, return the square root, squared
Matrix res = pow(n /
2
);
return
res.multiply(res);
}
else
{
// if n is even, return the matrix multiplied by the matrix to the (n - 1)th power
return
multiply(pow(n -
1
));
}
}
static long[][] multiply(long[][] A, long[][] B, long mod) { | |
long[][] C = new long[2][2]; | |
for (int i = 0; i < 2; ++i) | |
for (int j = 0; j < 2; ++j) | |
for (int k = 0; k < 2; ++k) | |
C[i][j] = (C[i][j] + ((A[i][k] % mod) * (B[k][j] % mod)) % mod) % mod; | |
return C; | |
} | |
static long[][] fastPow(long[][] base, long exp, long mod) { | |
if (exp < 0) | |
return new long[][]{{0, 0}, {0, 0}}; | |
if (exp == 0) | |
return new long[][]{{1, 0}, {0, 1}}; | |
if (exp == 1) | |
return base; | |
if (exp % 2 == 0) { | |
long[][] tmp = fastPow(base, exp / 2, mod); | |
return multiply(tmp, tmp, mod); | |
} else { | |
long[][] tmp = fastPow(base, (exp - 1) / 2, mod); | |
return multiply(base, multiply(tmp, tmp, mod), mod); | |
} | |
} | |
public static void main(String[] args) throws IOException { | |
BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); | |
String line; | |
while ((line = in.readLine()) != null) { | |
line = line.trim(); | |
String[] parts = line.split("[ ]+"); | |
long N = Long.parseLong(parts[0]); | |
int M = Integer.parseInt(parts[1]); | |
long MOD = (1L << M); | |
long[][] base = {{0L, 1L}, {1L, 1L}}; | |
long[][] pow = fastPow(base, N - 1, MOD); | |
long res = pow[1][1]; | |
System.out.println(res); | |
} | |
in.close(); | |
System.exit(0); | |
} |
public
static
int
[][] multiply(
int
[][] a,
int
[][] b) {
int
[][] res =
new
int
[a.length][a.length];
for
(
int
i =
0
; i < a.length; i++)
for
(
int
j =
0
; j < a.length; j++)
for
(
int
k =
0
; k < a.length; k++)
res[i][j] = ((res[i][j] + ((a[i][k] & mod) * (b[k][j] & mod))) & mod);
return
res;
}
public
static
int
[][] matPow(
int
[][] mat,
int
pow) {
int
[][] res =
new
int
[mat.length][mat.length];
for
(
int
i =
0
; i < res.length; i++)
res[i][i] =
1
;
while
(pow >
0
) {
if
(pow %
2
==
1
)
res = multiply(res, mat);
mat = multiply(mat, mat);
pow >>=
1
;
}
return
res;
}