Every matrix-exponentiation trick (huge Fibonacci numbers, linear recurrences, counting walks in a graph) sits on two small functions. Write them once, generically, with every entry reduced modulo mod:
mat_mul(A, B, mod) -> list[list[int]]: the product of ann × mmatrixAand anm × pmatrixB(lists of rows), entry(i, j)beingΣ A[i][t] · B[t][j]overt, taken% mod.mat_pow(M, e, mod) -> list[list[int]]:Mraised to the powerefor a squarek × kmatrix, modulomod.M^0is the identity matrix. Use repeated squaring:ecan be up to10^18, so multiplyingetimes is hopeless, but only aboutlog2(e) ≈ 60squarings are needed.
mat_mul([[1, 2], [3, 4]], [[5, 6], [7, 8]], 1000) # [[19, 22], [43, 50]]
mat_mul([[1, 2, 3]], [[4], [5], [6]], 10) # [[2]] (32 % 10)
mat_pow([[1, 1], [1, 0]], 10, 10**9 + 7) # [[89, 55], [55, 34]] (Fibonacci numbers)
mat_pow([[2, 0], [0, 3]], 0, 7) # [[1, 0], [0, 1]]
Don't modify the input matrices. Constraints: dimensions up to 8, 0 <= e <= 10^18, 1 <= mod <= 2·10^9, entries in [0, mod).
Show hint
Keep result = identity and base = M; while e > 0, if e & 1 do result = result · base, then base = base · base and e >>= 1.