简体   繁体   中英

Count number of subarrays whose product is not divisible by k

Given an array, I want to count the number of subarrays (contiguous) who's product when taken will not be divisible by k.

Eg. Let A = [1, 2, 3, 4, 5, 6] and K = 2

Then the number of subarrays such that the product is not divisible by K is 2:

{1}
{3}
{5}

Rest of them are all divisible by 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..

I tried first calculating the total number of subarrays (n)(n+1)/2 and then subtracting the number of subarrays that are divisible by k by using mod but it doesn't work. How do I get around this one?

This calculates (wrongly) number of subarrays who's product is divisible by 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;

A slightly related question is this one but it involves addition so it cannot be applied here.

Edit : constraints on array size is 10^5 and on array elements is 10^9. Hence, I'm looking for solution in linear or linearithmic time

The "big picture":

  1. It's easy to see that if the [l, r] subarray product is divisible by K , so is the product of [l, r + 1] and [l - 1, r] .

  2. Thus, if we could compute the value of the product of a subarray modulo K efficiently, we could just move two pointers (the left pointer goes right by exactly one and the right one keeps increasing until the product becomes equal to zero modulo K). This way, we would obtain the number of subarrays that start in the left pointer position and whose product is divisible by K. The answer would be just the sum over all values of the left pointer.

  3. Problem: we can't store the product explicitly (it's too large). We can't do modulo arithmetic either as moving the left pointer would require modulo division. We may not have an inverse.

Solution 1:

Let's use a segment tree to compute the product modulo K of an arbitrary subarray in O(log N) time (we just build the tree and store the product of the corresponding range modulo K in each node. Now we just need to multiply these values (modulo K) for all nodes that a query range is decomposed into). We can use two pointers because we can compute the product of any subarray modulo K efficiently.

Solution 2:

Divide and conquer.

Let's split the array into two (almost) equal halves and solve the problem for each of them recursively. Now we just need to count the number of good subarrays that start in the first half and end in the second one. But the product of each such subarray is the product of the [l, m] and [m + 1, r] parts (all computation are done modulo K). But m is fixed (it's the position where the split the array). Thus, we can precompute the products of [l, m] for all l and the products of [m + 1, r] for all r in linear time. Now we can use two pointers again (they are initialized with 0 and m + 1 , respectively). We can "merge" two halves in linear time, so the total time complexity is again O(N log N) .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM