Cho ma trận nhị phân và giá trị k. Cần chia ma trận thành k phần, mỗi phần chứa ít nhất một 1. Quy tắc cắt:
- Chọn hướng: dọc (vertical) hoặc ngang (horizontal)
- Chọn chỉ số cắt ma trận thành 2 phần
- Cắt dọc: không thể cắt phần trái, chỉ tiếp tục cắt phần phải
- Cắt ngang: không thể cắt phần trên, chỉ tiếp tục cắt phần dưới
Tìm số cách chia khác nhau. Kết quả modulo 109+7.
Ví dụ: ma trận 3×3, k=2 → output 4 (cắt dọc 2 cách, cắt ngang 2 cách).
Thuật toán DP + Prefix Sum:
- Tính
counts[i,j]= số lượng 1 trong submatrix từ (i,j) đến (m-1,n-1) (bottom-right) - Công thức:
counts[i,j] = counts[i+1,j] + counts[i,j+1] - counts[i+1,j+1] + matrix[i,j] - Hàm đệ quy
f(x, y, c): số cách cắt submatrix từ (x,y) thành c+1 phần - Base case:
c==0→ return 1 nếucount>0else 0 - Thử cắt ngang: duyệt
itừx+1đếnm-1, nếu0 < counts[i,y] < count→ans += f(i, y, c-1) - Thử cắt dọc: duyệt
jtừy+1đếnn-1, nếu0 < counts[x,j] < count→ans += f(x, j, c-1) - Return
ans % MOD
Triển khai
from collections import defaultdict
class Solution:
def solve(self, matrix, k):
MOD = 10**9 + 7
m, n = len(matrix), len(matrix[0])
counts = defaultdict(int)
# Prefix sum bottom-right
for i in range(m-1, -1, -1):
for j in range(n-1, -1, -1):
counts[(i, j)] = (counts[(i+1, j)] + counts[(i, j+1)]
- counts[(i+1, j+1)] + matrix[i][j])
def f(x, y, c):
count = counts[(x, y)]
if c == 0:
return 1 if count > 0 else 0
ans = 0
# Cắt ngang
for i in range(x+1, m):
if 0 < counts[(i, y)] < count:
ans += f(i, y, c-1)
# Cắt dọc
for j in range(y+1, n):
if 0 < counts[(x, j)] < count:
ans += f(x, j, c-1)
return ans % MOD
return f(0, 0, k-1)
ob = Solution()
matrix = [[1, 1, 0], [1, 0, 1], [1, 1, 1]]
k = 2
print(ob.solve(matrix, k))
Đầu vào
[[1, 1, 0], [1, 0, 1], [1, 1, 1]], 2
Đầu ra
4
Lưu ý: Có thể tối ưu bằng memoization (lru_cache) cho hàm f(x,y,c) vì có overlapping subproblems.