1

I am looking at this challenge:

You are provided an array A[ ] of N elements.
Also, you have to answer M queries.
Each query is of following type-

Given a value X, find A[1]%X + A[2]%X + ...... + A[N]%X

  • 1<=N<=100000
  • 1<=M<=100000
  • 1<=X<=100000
  • 1<=elements of array<=100000

I am having a problem in computing this value in an optimized way.
How can we compute this value for different X?

user249117
  • 37
  • 6
  • 1
    What have you tried? Have you seen any formula of modular arithmetics? – MBo Aug 24 '17 at 11:55
  • 1
    Formula I know of is - (A%X + B%X ) %X = (A+B)%X. I need only (A%X + B%X ) . I tried a lot to figure out if it is possible to obtain the sum of remainders. But I didn't get any formula. – user249117 Aug 24 '17 at 12:02
  • @harold No, that's incorrect as it'll give (A[1]%X + A[2]%X + ...... + A[N]%X )%X instead of A[1]%X + A[2]%X + ...... + A[N]%X. – Prince Aug 24 '17 at 12:55
  • @user249117 It is worth to include this information in question body to prevent hasty comments and answers. – MBo Aug 24 '17 at 13:36

2 Answers2

4

Here is a way that you could at least reduce the multiplicative factor in the time complexity.


In the C standard, the modulo (or remainder) is defined to be a % b = a - (a / b) * b (where / is integer division).

A naive, iterative way (possibly useful on embedded systems with no division unit) to compute the modulo is therefore (pseudo-code):

function remainder (A, B):
  rem = A
  while rem > B:
    rem -= B;
  return rem

But how does this help us at all? Suppose we:

  • Sort the array A[i] in ascending order
  • Pre-compute the sum of all elements in A[] -> S
  • Find the first element (with index I) greater than X
  • From the pseudocode above it is clear that at least (one multiple of) X must be subtracted from all elements in the array from index I onwards. Therefore we must subtract (N - I + 1) * X from the sum S.
    • Even better: we can keep a variable (call it K, initialize to zero) which is equal to the total multiple of X we must subtract from S to find the sum of all remainders. Thus at this stage we could simply add N - I + 1 to K.
  • Repeat the above, finding the first element greater than the next limit L = 2X, 3X, ... and so on, until we have passed the end of the array.
  • Finally, the result is given by S - K * X.

Pseudocode:

function findSumOfRemainder (A[N], X):
   sort A
   S = sum A
   K = 0
   L = X
   I = 0

   while I < N:
      I = lowest index such that A[I] >= L
      K += N - I + 1
      L += X

   return S - K * X

What is the best way to find I at each stage, and how does it relate to the time-complexity?

  1. Binary search: Since the entire array is sorted, to find the first index I at which A[I] >= L, we can just do a binary search on the array (or succeeding sub-array at each stage of the iteration, bounded by [I, N - 1]). This has complexity O( log[N - I + 1] ).

  2. Linear search: Self-explanatory - increment I until A[I] >= L, taking O( N - I + 1 )

You may dismiss the linear search method as being "stupid" - but let's look at the two different extreme cases. For simplicity we can assume that the values of A are "uniformly" distributed.

  • (max(A) / X) ~ N: We will have to compute very few values of I; binary search is the preferred method here because the complexity would be bounded by O([NX / max(A)] * log[N]), which is much better than that of linear search O(N).

  • (max(A) / X) << N: We will have to compute many values of I, each separated by only a few indices. In this case the total binary search complexity would be bounded by O(log N) + O(log[N-1]) + O(log[N-2]) + ... ~ O(N log N), which is significantly worse than that of linear search.

So which one do we choose? Well this is where I must get off, because I don't know what the optimal answer would be (if there even is one). But the best I can say is to set some threshold value for the ratio max(A) / X - if greater then choose binary search, else linear.


I welcome any comments on the above + possible improvements; the range constraint of the values may allow better methods for finding values of I (e.g. radix sort?).

meowgoesthedog
  • 14,670
  • 4
  • 27
  • 40
  • I tried almost similar approach, but this gets time out . – user249117 Aug 24 '17 at 14:10
  • @user249117 Have you tested the code separately (i.e. on local machine)? I don't mean to offend - but it may be an infinite loop or other logic error inside the code – meowgoesthedog Aug 24 '17 at 14:12
  • No No. It got partially accepted on small test cases, and doesn't time out on those. I tested it properly. When the multiples get large enough neither Binary search nor Linear search kinda approach fits. And I tried it through various thresholds as well. – user249117 Aug 24 '17 at 14:17
  • @user249117 please post your code; also, did you try to benchmark each stage of the algorithm? (it could be the sorting that's causing a timeout) – meowgoesthedog Aug 24 '17 at 14:20
0
#include<bits/stdc++.h>

using namespace std;

int main(){

    int t;

    cin >> t;

    while(t--){

        int n;

        cin >> n;

        int arr[n];

        long long int sum = 0;

        for(int i=0;i<n;i++){

            cin >> arr[i];

        }

        cout << accumulate(arr, arr+n, sum) - n << '\n';

    }

}

In case you don't know about accumulate refer this.

Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 11 '21 at 10:39