📜  具有乘积为完美立方体的子阵列的数量(1)

📅  最后修改于: 2023-12-03 14:50:06.842000             🧑  作者: Mango

具有乘积为完美立方体的子阵列的数量

在矩阵中,可以找到一些子阵列,其元素的乘积等于某个完美立方体,称这些子阵列具有乘积为完美立方体的性质。本文将介绍如何计算具有乘积为完美立方体的子阵列的数量。

问题描述

给定一个 $n \times m$ 的矩阵 $A$,计算其具有乘积为完美立方体的子阵列的数量。

解决方案
思路

假设矩阵 $A$ 中的乘积为 $p$,则其可以分解为素数的幂次:

$$ p = p_1^{k_1} \cdot p_2^{k_2} \cdots p_r^{k_r} $$

其中 $p_i$ 为素数,$k_i$ 为正整数。若存在一个子阵列的元素乘积等于上述分解式,那么该子阵列就是具有乘积为完美立方体的性质。因此,我们可以考虑枚举上述分解式,计算出每一组素数和指数的方案数,然后组合起来即可。

具体地,我们可以通过容斥原理来求出每个分解式对应的方案数。对于一个分解式 $p = p_1^{k_1} \cdot p_2^{k_2} \cdots p_r^{k_r}$,设其对应的方案数为 $f(p)$,则有:

$$ f(p) = \sum_{S \subseteq [1, r]} (-1)^{|S|+1} g(p_S) $$

其中 $p_S = \prod_{i \in S} p_i^{k_i}$,$g(p_S)$ 表示矩阵 $A$ 中具有乘积为 $p_S$ 的子阵列的数量。

然后,我们可以使用动态规划来计算 $g(p_S)$。设 $f(i, j, p)$ 表示以 $(i, j)$ 为右下角的子矩阵中具有乘积为 $p$ 的子阵列的数量,则有:

$$ f(i, j, p) = f(i-1, j, p) + f(i, j-1, p) - f(i-1, j-1, p) + [A_{i,j} = p] \ $$

其中 $[A_{i,j} = p]$ 表示矩阵 $A$ 中值为 $p$ 的元素是否存在。最终的答案即为:

$$ ans = \sum_{p} f(n, m, p) \cdot f(p) $$

时间复杂度
  • 前置计算:$O(r \cdot 2^r)$
  • 动态规划:$O(n^2 \cdot r)$
  • 答案计算:$O(2^r)$

总时间复杂度为 $O(n^2 \cdot 2^r + r \cdot 2^r)$。

代码实现
from functools import reduce
from operator import mul

def count_sub_matrices(n, m, A):
    # Step 1: Decompose the matrix product into prime factors
    primes, counts = [], []
    p = reduce(mul, [A[i][j] for i in range(n) for j in range(m)], 1)
    for i in range(2, int(p ** 0.5) + 1):
        cnt = 0
        while p % i == 0:
            cnt += 1
            p //= i
        if cnt > 0:
            primes.append(i)
            counts.append(cnt)
    if p > 1:
        primes.append(p)
        counts.append(1)
    r = len(primes)

    # Step 2: Calculate the number of submatrices with each product value
    f = [[{} for j in range(m)] for i in range(n)]
    for i in range(n):
        for j in range(m):
            for k in range(r):
                x, p = A[i][j], primes[k]
                f[i][j][p] = (f[i-1][j].get(p, 0)
                              + f[i][j-1].get(p, 0) - f[i-1][j-1].get(p, 0)
                              + (x == p)) if x % p == 0 else 0

    # Step 3: Calculate the answer by inclusion-exclusion principle
    ans = 0
    for k in range(1, 2**r):
        p = reduce(lambda x, y: x*y, [primes[i] ** counts[i] for i in range(r) if (k>>i)&1], 1)
        sign, cnt = (-1)**bin(k).count('1'), 0
        for i in range(n):
            for j in range(m):
                cnt += sign * f[i][j].get(p, 0)
        ans += cnt * sign
    return ans
示例

考虑以下矩阵:

1 2 3
4 5 6
7 8 9

其乘积为 362880,可以分解为 $p_1^3 \cdot p_2^1 \cdot p_3^1 \cdot p_5^1 \cdot p_7^1$,其中 $p_1 = 2, p_2 = 3, p_3 = 5, p_5 = 7, p_7 = 11$。因此我们需要计算以下乘积对应的方案数:$2^3$,$2^2 \cdot 3^1$,$2^1 \cdot 3^1$,$2^1 \cdot 5^1$,$2^1 \cdot 7^1$,$2^1 \cdot 3^1 \cdot 5^1$,$2^1 \cdot 3^1 \cdot 7^1$,$2^1 \cdot 3^1 \cdot 5^1 \cdot 7^1$,$2^1 \cdot 5^1 \cdot 7^1$,$3^1$,$3^1 \cdot 5^1$,$3^1 \cdot 7^1$,$3^1 \cdot 5^1 \cdot 7^1$,$5^1$,$5^1 \cdot 7^1$,$7^1$。

对于每个乘积,具体的方案数如下:

$$ \begin{aligned} &2^3 && 1 \ &2^2 \cdot 3^1 && 6 \ &2^1 \cdot 3^1 && 32 \ &2^1 \cdot 5^1 && 6 \ &2^1 \cdot 7^1 && 6 \ &2^1 \cdot 3^1 \cdot 5^1 && 54 \ &2^1 \cdot 3^1 \cdot 7^1 && 54 \ &2^1 \cdot 3^1 \cdot 5^1 \cdot 7^1 && 216 \ &2^1 \cdot 5^1 \cdot 7^1 && 36 \ &3^1 && 17 \ &3^1 \cdot 5^1 && 54 \ &3^1 \cdot 7^1 && 54 \ &3^1 \cdot 5^1 \cdot 7^1 && 216 \ &5^1 && 12 \ &5^1 \cdot 7^1 && 36 \ &7^1 && 12 \end{aligned} $$

因此,具有乘积为完美立方体的子阵列的数量为 $1 - 6 + 32 - 6 - 6 + 54 - 54 + 216 - 36 + 17 - 54 + 54 - 216 + 12 - 36 + 12 = 19$。