Given an integer n >= 1, compute the number of different tilings of a 4 × n board using 2 × 1 dominoes. Dominoes may be placed horizontally or vertically; all tiles must fully cover the board without overlap.
Input: n =2Output: 5Explanation: There are five tilings of a 4×2 board — all-vertical, and four patterns with two horizontal dominoes occupying one of the two rows(symmetries accounted for). Small enumeration:1) All vertical dominoes(one per column)2) Two horizontals covering top two cells and two verticals below
3) Two horizontals covering second row, verticals elsewhere
4) Two horizontals covering third row, verticals elsewhere
5) Two horizontals covering bottom row, verticals elsewhere(Total =5)
We present a concise derivation of the standard linear recurrence for f(n) (the number of tilings) and two practical algorithms: a linear DP and a fast matrix-exponentiation method for large n.
Look at how a tiling of the 4 × n board can begin at the leftmost columns. There are a fixed set of local starting patterns (eight canonical types). Group tilings by their starting pattern and relate f(n) to values f(k) for smaller k by removing covered columns; this yields a linear recurrence.
Let f(n) be the number of tilings of a 4 × n board. Handle small n by inspection:
f(1) = 1, f(2) = 5, f(3) = 11, f(4) = 36.
Enumerate the distinct ways a valid tiling can occupy the leftmost 1–4 columns (these are the eight starting types A..H in the classical derivation).
Count contributions from each type and express f(n) in terms of f(n-1), f(n-2), f(n-3), and f(n-4).
Simplifying the combinatorial bookkeeping gives the recurrence
f(n) = f(n-1) + 5*f(n-2) + f(n-3) - f(n-4)
with base values listed above.
This recurrence is classical; a clear derivation follows by grouping types and using inclusion/exclusion on the dependent patterns (see references in source_links).
classSolution {
publiclongfillingBlocks(int n) {
if (n <= 0) return 0;
if (n == 1) return 1;
if (n == 2) return 5;
if (n == 3) return 11;
if (n == 4) return 36;
finallong MOD = 1_000_000_007L;
long[] f =newlong[n+1];
f[1]=1; f[2]=5; f[3]=11; f[4]=36;
for (int i = 5; i <= n; ++i) {
long v = (f[i-1]+ 5*f[i-2]+ f[i-3]- f[i-4]) % MOD;
if (v < 0) v += MOD;
f[i]= v;
}
return f[n];
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from typing import List
classSolution:
deffilling_blocks(self, n: int) -> int:
if n <=0: return0if n ==1: return1if n ==2: return5if n ==3: return11if n ==4: return36 MOD =10**9+7 f = [0] * (n+1)
f[1], f[2], f[3], f[4] =1, 5, 11, 36for i in range(5, n+1):
v = f[i-1] +5*f[i-2] + f[i-3] - f[i-4]
v %= MOD
f[i] = v
return f[n]
The recurrence is linear with constant coefficients of order 4. We can express the state vector S(i) = [f(i), f(i-1), f(i-2), f(i-3)]^T and a fixed 4×4 transition matrix M such that S(i+1) = M * S(i). Then S(n) = M^{n-4} * S(4) and we can compute M^{n} in O(log n) matrix multiplications.
classSolution {
public:using ll =longlong;
const ll MOD =1000000007LL;
vector<vector<ll>> mul(const vector<vector<ll>>& A, const vector<vector<ll>>& B) {
int m =4;
vector<vector<ll>> C(m, vector<ll>(m));
for (int i =0; i < m; ++i)
for (int k =0; k < m; ++k)
for (int j =0; j < m; ++j)
C[i][j] = (C[i][j] + A[i][k]*B[k][j]) % MOD;
return C;
}
vector<vector<ll>> mpow(vector<vector<ll>> base, longlong e) {
int m =4;
vector<vector<ll>> res(m, vector<ll>(m));
for (int i =0; i < m; ++i) res[i][i] =1;
while (e >0) {
if (e &1) res = mul(res, base);
base = mul(base, base);
e >>=1;
}
return res;
}
longlongfillingBlocksFast(longlong n) {
if (n <=0) return0;
if (n ==1) return1;
if (n ==2) return5;
if (n ==3) return11;
if (n ==4) return36;
vector<vector<ll>> M = {
{1,5,1,MOD-1},
{1,0,0,0},
{0,1,0,0},
{0,0,1,0}
};
auto P = mpow(M, n-4);
vector<ll> S4 = {36,11,5,1};
ll ans =0;
for (int j =0; j <4; ++j) ans = (ans + P[0][j]*S4[j]) % MOD;
return ans;
}
};
from typing import List
classSolution:
MOD =10**9+7defmat_mul(self, A: List[List[int]], B: List[List[int]]) -> List[List[int]]:
m =4 C = [[0]*m for _ in range(m)]
for i in range(m):
for k in range(m):
for j in range(m):
C[i][j] = (C[i][j] + A[i][k]*B[k][j]) % self.MOD
return C
defmat_pow(self, base: List[List[int]], e: int) -> List[List[int]]:
m =4 res = [[0]*m for _ in range(m)]
for i in range(m): res[i][i] =1while e >0:
if e &1:
res = self.mat_mul(res, base)
base = self.mat_mul(base, base)
e >>=1return res
deffilling_blocks_fast(self, n: int) -> int:
if n <=0: return0if n ==1: return1if n ==2: return5if n ==3: return11if n ==4: return36 M = [
[1,5,1,(self.MOD-1)],
[1,0,0,0],
[0,1,0,0],
[0,0,1,0]
]
P = self.mat_pow(M, n-4)
S4 = [36,11,5,1]
ans =0for j in range(4):
ans = (ans + P[0][j]*S4[j]) % self.MOD
return ans
⏰ Time complexity: O(log n) for the matrix-exponentiation method (each multiplication is constant-sized 4×4 work, exponentiation takes O(log n) steps).
🧺 Space complexity: O(1) (constant extra space for matrices) beyond input/output.