题目描述
思路
我们假设我们可以在O(1)时间内计算一个子矩阵内是否有苹果(这可以使用二维前缀和解决,但是我们现将这个问题放在一边,我们先考虑DP的事情)
整个矩阵是n行m列。假如下标从1开始,我们现在剩余c刀,对于左上角在(i,j)右下角在(n,m)的子矩阵而言:
-
在第
hc的位置切一刀:将[i:hc , j:m]子矩阵划分出去,剩余子矩阵为[hc+1:n , j:m]。那么问题变成了使用c-1刀切分[hc+1:n , j:m] -
在第
vc的位置切一刀:将[i:n , j:vc]子矩阵划分出去,剩余子矩阵为[i:n , vc+1:m]。 那么问题变成了使用c-1刀切分[i:n , vc+1:m] -
递归边界就是
c==0,此时检查剩余矩阵是否有元素。如果有就是一个合法的方案。 -
可以切一刀的条件就是,你
划分出去的子矩阵里面有元素,就可以切一刀。我们就加上这个子问题的答案。 -
我们每次查询区间
[x1:x2,y1:y2]子矩阵(x1行和x2行均在子矩阵中,y1列和y2列也均在子矩阵中)是否有元素,使用二维前缀和可以O(1)时间做到。
代码
class Solution:
def ways(self, pizza: List[str], k: int) -> int:
MOD = int(1e9) + 7
n , m = len(pizza) , len(pizza[0])
prefix2d = [ [0] * (m+1) for _ in range(n+1)]
for i in range(1,n+1) :
for j in range(1,m+1) :
prefix2d[i][j] = prefix2d[i-1][j] + prefix2d[i][j-1] - prefix2d[i-1][j-1] + (pizza[i-1][j-1] == 'A')
def query(x1,y1,x2,y2): # 下标从1开始 [x1,y1][x2,y2]子矩阵闭区间
return (prefix2d[x2][y2] - prefix2d[x2][y1-1] - prefix2d[x1-1][y2] + prefix2d[x1-1][y1-1]) > 0
@cache
def dfs(i : int , j : int , c : int) -> int :
if c == 0 :
return 1 if query(i,j,n,m) else 0
res = 0
for hc in range(i,n) :
if query(i,j,hc,m) :
res = (res + dfs(hc+1,j,c-1)) % MOD
for vc in range(j,m) :
if query(i,j,n,vc) :
res = (res + dfs(i,vc+1,c-1)) % MOD
return res % MOD
return dfs(1,1,k-1)