Linear Recurrence / Matrix Exponentiation¶
This lane is for the moment when an ordinary DP recurrence is correct but the index n is too large to iterate one step at a time.
The key shift is:
- stop thinking of "next value" as one scalar update
- package the last
kvalues into one state vector - express one step as multiplication by one fixed matrix
- jump many steps by exponentiating that matrix
For contest work, this is the first exact route when the problem really says:
the transition is linear, the state dimension is small, and n can be huge
At A Glance¶
- Use when: one state is a fixed linear combination of a constant number of previous states, or one small linear state transition repeats many times
- Core worldview: one step is one matrix
T; many steps areT^p - Main tools: state vector, companion matrix, binary exponentiation on matrices
- Typical complexity:
O(k^3 log n)for ak x kmatrix - Main trap: building the right recurrence but ordering the state vector incorrectly
Strong contest signals:
nis up to10^18or similarly too large for linear DP- the recurrence has constant width, like
f(n) = c1 f(n-1) + ... + ck f(n-k) - the statement is really "apply the same linear transition many times"
- a graph path count with exactly
kedges can be written as repeated multiplication by one adjacency matrix
Strong anti-cues:
- the transition is not linear after algebraic cleanup
- the state dimension is large enough that
k^3 log nis already too expensive - the recurrence is special enough for a lighter route like Fibonacci fast doubling
- the task is ordinary small-
nDP and you are about to overbuild
Prerequisites¶
Helpful neighboring topics:
- DP Foundations if the hard part is still identifying the right repeated state
- Number Theory Basics if modulo arithmetic and overflow discipline still feel shaky
- Convex Hull Trick / Li Chao Tree as a compare point for "DP transition becomes another algebraic object"
Problem Model And Notation¶
Suppose the state we want is f(n), and there exists a fixed recurrence:
for all large enough n.
Define the state vector:
Then one step of the recurrence can be written as:
for one fixed k x k matrix T.
That immediately gives:
So once the state is linear and fixed-width, the problem becomes:
- build
T - exponentiate
T - multiply by one base state vector
From Brute Force To The Right Idea¶
Brute Force¶
If we compute the recurrence one index at a time, the running time is:
That is fine for:
n <= 2 * 10^6
but hopeless for:
n <= 10^18
Structural Observation¶
The recurrence does not change from one step to the next.
That is the real opening.
If one step always transforms:
current state vector -> next state vector
in the same linear way, then we are repeatedly applying the same operator.
Repeated application of one linear operator is exactly what matrix powers model.
Why Binary Exponentiation Helps¶
Ordinary repeated squaring says:
can be computed in O(log n) multiplications.
The same idea works for matrices:
can be computed in O(log n) matrix multiplications.
So the giant index disappears from the loop count.
Only the state dimension remains.
Core Invariant And Why It Works¶
1. State Vector Meaning¶
Choose a state ordering and never drift from it.
For the usual recurrence lane:
means:
the first coordinate is the newest term
the last coordinate is the oldest term still needed next step
Everything else depends on preserving that meaning.
2. Companion Matrix Meaning¶
For a k-order recurrence, the first row of T computes the new term.
The remaining rows usually just shift the window:
So the standard companion matrix has:
- recurrence coefficients in the first row
1s on the subdiagonal
That is not a trick. It is just the algebraic encoding of:
compute one new value, then shift the window down by one slot
3. Why Powers Encode Many Steps¶
If:
then:
and by induction:
So exponentiating T is exactly the same as applying the recurrence p times.
4. Why Complexity Is Small Enough¶
For a dense k x k matrix:
- one multiplication costs
O(k^3) - exponentiation needs
O(log n)multiplications
Therefore the standard route is:
This is excellent when:
kis small, like2,6,20, or even50
and usually poor when:
kis large enough that cubic work dominates
Variant Chooser¶
Use Ordinary DP When¶
nis small enough to iterate directly- the recurrence width is small but there is no need to jump huge distances
This is the clean route for the warm-up problem:
Use Matrix Exponentiation When¶
- the recurrence width is fixed and small
- the same linear transition repeats many times
nis huge, often10^18
This is the first exact route for:
Use A Specialized Formula When¶
- the recurrence has extra structure
Example:
- Fibonacci numbers can be done by a
2 x 2matrix - but fast doubling is lighter and faster if the task is only Fibonacci
So matrix exponentiation is the general route, not always the lightest route.
Reopen The Topic Before Reusing The Starter When¶
- the transition is matrix-shaped but the matrix dimension is large
- the matrix is sparse enough that a custom multiply should replace the dense
O(k^3)multiply - you really need a stronger recurrence tool like Berlekamp-Massey / Kitamasa
That is now a shipped follow-up lane, not part of this first matrix route.
Worked Examples¶
1. Fibonacci¶
The recurrence is:
Use state:
Then:
So:
This is the smallest clean example of the whole lane.
2. Throwing Dice¶
Let f(n) be the number of ordered dice sequences summing to n.
Then:
with:
and f(n) = 0 for negative n.
Take:
Then:
where the first row is all 1s, and the remaining rows shift the window.
So Throwing Dice is not "just a math problem."
It is the first canonical order-6 recurrence -> companion matrix route.
3. Matrix Transition On A Graph¶
If A is an adjacency matrix, then:
counts walks of length k from u to v.
This is the same worldview:
- one step is one fixed linear transition
- many steps are one matrix power
That is a useful compare point once the recurrence version already feels natural.
Pseudocode¶
build transition matrix T
build base state vector S(base_index)
if n <= base_index:
return direct base answer
P = mat_pow(T, n - base_index)
answer_state = P * S(base_index)
return answer_state[0]
Implementation Notes¶
- Keep the state-vector order explicit in comments while building the matrix.
- If the problem is modulo
MOD, reduce after every matrix cell update. - Use
__int128inside multiplication ifMODor coefficients can makea * boverflowlong long. - Dense matrix multiplication is fine for small
k; do not overengineer sparse variants too early. - For contest code, make the starter generic enough for one matrix and one vector, but not so generic that the invariant disappears.
- The base vector should be chosen at the first index where every coordinate you need is already known.
Repo Anchors¶
- Topic-adjacent note: Throwing Dice
- Starter template:
matrix-exponentiation.cpp - Retrieval page: Linear Recurrence hot sheet
- Compare point:
- Modular Arithmetic
- CSES - Graph Paths I for the same repeated-linear-transition idea on an adjacency matrix
References¶
- Reference: cp-algorithms - Fibonacci Numbers
- Reference: Competitive Programmer's Handbook
- Practice: CSES - Fibonacci Numbers
- Practice: CSES - Throwing Dice
- Practice: CSES - Graph Paths I