0

This is my try to count the contiguous subsequences of an array with product mod 4 is not equal to 2:

# include <iostream>
using namespace std;

int main() {

        long long int n, i, j, s, t, count = 0;

        cin>>n;
        long long int arr[n];

        count = 0;
        for(i = 0; i<n; i++) {
            cin>>arr[i];
        }

            for(i = 0; i<n; i++) {
            s = 1;
            for(j = i; j<n; j++) {
                s = s*arr[j];
                if(s%4!=2) {
                    count++;
                }
            }
        }
        cout<<count;
    return 0;
}

However, I want to reduce the time taken by my code to execute. I am looking for a way to do it. Any help/hint would be appreciated. Thank you.

What does this definition of contiguous subsequences mean?

Infinity
  • 153
  • 2
  • 10
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/211393/discussion-on-question-by-infinity-how-do-optimize-my-code-to-find-product-of-al). – Bhargav Rao Apr 10 '20 at 21:49

1 Answers1

1

Listing all the subsequences

Suppose we have the sequence:

A B C D E F

First of all, we should recognize that there is one substring for every unique start and end point. Let's use the notation C-F to mean all items from C through F: i.e.: C D E F.

We can list all subsequences in a triangular arrangement like this:

A     B     C     D     E     F
  A-B   B-C   C-D   D-E   E-F
     A-C   B-D   C-E   D-F
        A-D   B-E   C-F
           A-E   B-F
              A-F
  • The first row lists all the subsequences of length 1.
  • The second row lists all the subsequences of length 2.
  • The third row lists all the subsequences of length 3. Etc.
  • The last row is the full sequence.

Modular arithmetic

Computing the product MOD 4 of a set of numbers

To figure out the product of a bunch of numbers MOD 4, we just need to look at each element of the set MOD 4. Intuitively, this is because when you multiply a bunch of numbers, the last digit of the result is determined entirely by the last digit of each factor. In this case "the last digit base 4" is the number mod 4.

The identity we are using is:

(A * B) MOD N == ((A MOD N) * (B MOD N)) MOD N

The table of products

Now we also have to look at the matrix of possible multiplications that might happen. It's a fairly small table and the interesting entries are given here:

  • 2 * 2 = 4 4 MOD 4 = 0
  • 2 * 3 = 6 6 MOD 4 = 2
  • 3 * 3 = 9 9 MOD 4 = 1

So the results of multiplying any 2 numbers MOD 4 are given by this table:

+--------+---+---+---+---+
| Factor | 0 | 1 | 2 | 3 |
+--------+---+---+---+---+
|      0 | 0 | / | / | / |
|      1 | 0 | 1 | / | / |
|      2 | 0 | 2 | 0 | / |
|      3 | 0 | 3 | 2 | 1 |
+--------+---+---+---+---+

The /'s are omitted because of the symmetry of multiplication (A * B = B * A)

An example sequence

Now for each subsequence, let's compute the product MOD 4 of its elements.

Consider the following list of numbers

242 497 681 685 410 795

The first thing we do is take all these numbers MOD 4 and list them as the first row of our list of all subsequences triangle.

2 0 1 1 2 3

The second row is just the product of the pairs above it.

2 0 1 1 2 3
 0 0 1 2 3

In general, the Nth element of each row is the product, MOD 4, of:

  • the number just to its left in the row above left times and
  • the element in the first row that is diagonally to its right

For example C = A * B

* * * * B *
 * * * / *
  * A / *
   * C *
    * *
     *

Again,

  • A is immediately up and left of C
  • B is diagonally right all the way to the top row from C

Now we can complete our triangle

2 0 1 1 2 3
 0 0 1 2 3
  0 0 2 3
   0 0 2
    0 0
     0

This can be computed easily in O(n^2) time.

Optimization

These optimizations do not improve the time complexity of the algorithm in its worse case, but can cause an early exit in the computation, and should therefore be included if time is to be reduced and the input is unknown.

Contageous 0's

Furthermore, as a matter of optimization, notice how contagious the 0's are. Anything times 0 is 0, so you can skip computing products of cells below a 0. In your case those sequences will not equal 2 MOD 4 once the product of one of its subsequences is determined to be equal to 0 MOD 4.

* * * 0 * *  // <-- this zero infects all cells below it
 * * 0 0 *
  * 0 0 0
   0 0 0
    0 0
     0

Need a 2 to make a 2.

Look back at the table of factors and products. Notice that the only way to get a product that is equal to 2 MOD 4 is to have one of the factors be equal to 2 MOD 4. What that means is that there can only be a 2 below another 2. So we are only interested in following computing entries in the table that are below a 2. Other entries in rows below can never become a 2.

You don't have to store more than the whole rows.

You only need O(n) storage to implement this. Working line by line, you can compute the values in a row entirely from the values in the first row and values in the row above.

Reading the answers from the table

Now you can look at the rows of the triangle list as you generate them and read off which subsequences are to be included.

Entries with a 2 are to be excluded. All others are to be included.

2 0 1 1 3 2
 0 0 1 3 2
  0 0 3 2
   0 0 2
    0 0
     0

The excluded subsequences for the example (which I will list only because there are fewer of them in my example) are:

  • A
  • F
  • E-F
  • D-F
  • C-F

Which remember, according to our convention refer to the elements:

  • A
  • F
  • E F
  • D E F
  • C D E F

Which are:

  • 242
  • 795
  • 410 795
  • 685 410 795
  • 681 685 410 795

Hopefully it's obvious how to display the "included" sequences, rather than the "excluded" sequences, as I have shown above.

Displaying all the elements makes it take much longer.

Sadly, actually displaying all of the elements of such subsequences is still an O(N^3) operation in the worst case. (Imagine a sequence of all zeros.)

Summary

For me, I feel like an average developer could take the magic bullet observation made in the diagram below and write an implementation that has optimal time complexity.

C = A * B

* * * * B *
 * * * / *
  * A / *
   * C *
    * *
     *
Wyck
  • 10,311
  • 6
  • 39
  • 60