给定一个数组,我想计算在拍摄时产品的子阵列(连续)的数量不能被k整除。
EG。设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。因此,我正在寻找线性或线性时间的解决方案
答案 0 :(得分:1)
“大局”:
很容易看出,如果[l, r]
子阵列产品可以被K
整除,那么[l, r + 1]
和[l - 1, r]
的乘积也是如此。
因此,如果我们能够有效地计算子模K的乘积的值,我们就可以移动两个指针(左指针正好向右移动一个,而右指针一直在增加,直到产品变得相等零模K)。这样,我们将获得从左指针位置开始并且其乘积可被K整除的子数组的数量。答案将只是左指针的所有值的总和。
问题:我们无法明确存储产品(它太大了)。我们不能做模运算,因为移动左指针需要模除法。我们可能没有逆。
解决方案1:
让我们使用一个分段树来计算O(log N)
时间内任意子阵列的产品模K(我们只需构建树并在每个节点中存储相应范围模K的乘积。现在我们只需要将查询范围分解为的所有节点乘以这些值(模K)。我们可以使用两个指针,因为我们可以有效地计算任何子模K的乘积。
解决方案2:
分而治之。
让我们将数组分成两个(几乎)相等的一半,并递归地解决每个数组的问题。现在我们只需要计算从上半部分开始到第二部分结束的良好子数组的数量。但是每个这样的子阵列的乘积是[l, m]
和[m + 1, r]
部分的乘积(所有计算都以K为模)。但是m
是固定的(它是拆分数组的位置)。因此,我们可以在线性时间内对所有[l, m]
的{{1}}和所有l
的{{1}}的产品进行预计算。现在我们可以再次使用两个指针(它们分别用0和[m + 1, r]
初始化)。我们可以在线性时间内“合并”两半,因此总时间复杂度再次为r
。