【问题标题】:Count number of subarrays whose product is not divisible by k计算其乘积不能被 k 整除的子数组的数量
【发布时间】:2016-11-21 11:52:54
【问题描述】:

给定一个数组,我想计算其乘积不能被 k 整除的子数组(连续)的数量。

例如。设 A = [1, 2, 3, 4, 5, 6] 和 K = 2

那么乘积不能被K整除的子数组的个数为2:

{1}
{3}
{5}

其余的都可以被 2 整除。

{1, 2}
{1, 2, 3}
{1, 2, 3, 4}
{1, 2, 3, 4, 5}
{1, 2, 3, 4, 5, 6}
{2}
{2, 3}
{2, 3, 4}
{2, 3, 4, 5} etc..

我尝试首先计算子数组的总数 (n)(n+1)/2,然后使用 mod 减去可被 k 整除的子数组的数量,但它不起作用。我该如何解决这个问题?

这会计算(错误地)乘积可被 K 整除的子数组的数量:

int curr = 1;
    int x = 0;
    for (int i = 0; i < a.length; i++) {
        curr = curr * a[i] % k;
        if (curr == 0) {
            curr = 1;
            if (x > 0)
                ans = ans.subtract(NumberUtils.nChooseR(x + 1, 2));
            if (a[i] % k != 0) {
                x = 1;
            } else {
                x = 0;
            }
        } else {
            x++;
        }
    }
    if (x != 0) {
        ans = ans.subtract(NumberUtils.nChooseR(x + 1, 2));
    }
    return ans;

一个稍微相关的问题是this one,但它涉及到加法,所以不能在这里应用。

编辑:数组大小限制为 10^5,数组元素限制为 10^9。因此,我正在寻找线性或线性时间的解决方案

【问题讨论】:

  • 什么是子数组?它应该只包含一项吗?如果不是,为什么{3, 5} 不是解决方案?
  • 遇到K = 4的解决办法是什么? {1}, {2}, {3, {5}{1}, {3}, {5}, {6}?
  • @DmitryBychenko by subarray 我的意思是连续的元素集
  • 子数组的生产是什么?例如。 {1, 3} x {5, 7} 是什么?
  • @DmitryBychenko 我不确定你所说的生产是什么意思,但如果你问我如何将这些元素相乘,就像这样:如果数组是:[3,5,8] K 为 2,则其值为 3x5x8 = 120,可被 2 整除,这意味着这是一个有效的子数组。另一方面,如果 array = [1, 7, 11] 它的值是 77,它不能被 2 整除,所以它是一个无效的子数组

标签: arrays algorithm


【解决方案1】:

“大局”:

  1. 很容易看出,如果[l, r] 子数组的乘积可以被K 整除,那么[l, r + 1][l - 1, r] 的乘积也是如此。

  2. 1234563到零模 K)。这样,我们将获得从左指针位置开始并且其乘积可以被 K 整除的子数组的数量。答案将只是左指针所有值的总和。
  3. 问题:我们无法明确存储产品(它太大)。我们也不能进行模运算,因为移动左指针需要模除法。我们可能没有逆。

解决方案 1:

让我们使用分段树来计算任意子数组在O(log N)时间的乘积模K(我们只是构建树并将相应范围模K的乘积存储在每个节点中。现在我们只需将这些相乘查询范围分解成的所有节点的值(模 K)。我们可以使用两个指针,因为我们可以有效地计算任何子数组模 K 的乘积。

解决方案 2:

分而治之。

让我们将数组分成(几乎)相等的两半,并递归地解决每一半的问题。现在我们只需要计算从前半部分开始到第二部分结束的好的子数组的数量。但是每个这样的子数组的乘积是[l, m][m + 1, r] 部分的乘积(所有计算都以 K 为模)。但是m 是固定的(它是拆分数组的位置)。因此,我们可以在线性时间内预先计算所有l[l, m] 的乘积和所有r[m + 1, r] 的乘积。现在我们可以再次使用两个指针(它们分别初始化为 0 和 m + 1)。我们可以在线性时间内“合并”两半,所以总时间复杂度又是O(N log N)

【讨论】:

  • 我认为分段树的想法会奏效,会实施并更新您
  • 在双指针方法中,您说我们需要使用 L 和 R 然后将 L 递减一次并递增 R 直到乘积可以被 K 整除,在哪里初始化指针?我不确定它是如何工作的,并且在不到 n 平方的时间内运行,你能详细说明一下吗?编辑:实际上左指针移动 right 一次,右指针向右移动,直到乘积为 0 mod k。而且,一旦答案是 0 mod k,你甚至不需要增加右指针,因为答案 将是 0 直到数组的末尾。请在答案中编辑此内容
  • 不幸的是,指针算法太慢了。但后来我意识到将左指针向右移动一次是非常无效的。你应该这样做:当乘积 not 0,rightpointer++, 而乘积 is 0 rightPointer++ 和 ans = ans + size - rightPointer。完整的代码在这里:dpaste.de/XJhQ 请将其包含在答案中以使其独立。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-12
  • 2012-07-31
  • 2015-12-22
  • 1970-01-01
  • 1970-01-01
  • 2020-07-17
  • 1970-01-01
相关资源
最近更新 更多