user216112
user216112

Reputation: 105

Sum of integer Division matrix

Here is a question from previous HackerEarth Challenge -

Roy has a matrix of size NxN. Rows and Columns are numbered from 1 to N. jth column of ith row contains integer division i/j.

In other words, Matrix[i][j] = int(i/j) where 1 ≤ i, j ≤ N.

Your task is to find sum of this matrix i.e.

sum = 0
for i=1 to N-1
    for j=1 to N-1
        sum += Matrix[i][j]
Constraints:
1 ≤ T ≤ 10
1 ≤ N ≤ 1000000

and here is my solution to this problem

#include <cstdio>
#include <cassert>
using namespace std;
#define MAXT 10
#define MAXN 1000000
long long solve(long long N){
    long long ans = 0;
    for(int i=1;i<N-1;i++)
    {
    for(int j=1; j<N-1 ; j++)
    {
        int temp = N*i/j;
        ans = ans + temp;
    }
    }
    return ans;
}
int main(){
    int T, N;
    scanf("%d", &T);
    assert(T>0 and T<=MAXT);
    while(T--){
        scanf("%d", &N);
        assert(N>0 and N<=MAXN);
        printf("%lld\n", solve((long long)N));
    }
    return 0;
}

But the output of this program is not coming correct.

So please tell me if I have achieved things here correctly. If yes what else can I do to optimize this code. Thanks for your help.

enter image description here

Upvotes: 0

Views: 738

Answers (4)

VolAnd
VolAnd

Reputation: 6407

Pay attention on for-loop condition

for i=1 to N-1  // in pseudo code

should be

for(int i=1;i < N;i++)

or

for(int i=1;i <= N-1;i++)

But NOT for(int i=1;i < N-1;i++) (that option loses the last item).

Next, expressions like i/j with integers are integer division that has only integer part of result (without rounding). This will lead to 0 value if i < j.

And the last one, summarizing expression should be (from sum += Matrix[i][j]) as

ans += Matrix[i][j];

BUT where is your matrix?

UPDATE

If for same reasons, you use expression N*i/j instead of values from matrix (Matrix[i][j]), and you defensively want to use integer arithmetic you can minimize the code as:

long long solve(long long N){
    long long ans = 0;
    for (int i = 1; i < N; i++)
    {
        for (int j = 1; j < N; j++)
        {
            ans += N * i / j;
        }
    }
    return ans;
}

at the same time you should understand that long long cannot save you from arithmetic overflow when N > 1000000

UPDATE 2:

Check the task about 1 ≤ i, j ≤ N and if it is really <= N try changes for both for as

   for (int i = 1; i <= N; i++)
    {
        for (int j = 1; j <= i; j++)
        {
             ans += i / j;
        }
    }

Upvotes: 1

Rishikesh Raje
Rishikesh Raje

Reputation: 8614

Note that int(i/j) does not change much for larger values of j

i.e. if j = 1000 int(i/j) will be 0 for 1-1000, then it will be 1 for 1000-2000, and so on. Using this fact, you can create an algorithm with much lower complexity.

e.g. if N = 50000, then for j = 1000, you will get 0... (1000) times + 1 ..(1000) times + 2..(1000) times.... upto 49,000/1000... (1000) times.

i.e. div = N/j ans += (div *(div-1) *j)

You also need to make a correction if N/j is not a whole number as shown in the code below.

long long solve(long long N){
    long long ans = 0;
    long long div, mod;
    for (int i = 1; i <= N; i++)
    {
        div = N/i;
        mod = i- N%i;
        ans += (div * (div+1) * i)/2;

        // For the case when N does not go directly into i,
        // e.g. N = 47500, i = 1000, the last 500 need to be removed from the sum
        ans -= (mod-1) * div;
        printf ("\n i = %d, ans = %lld",i,ans);
    }
    return ans;
}

This is O(n) complexity.

Edit: Corrected to fix expected results.

Upvotes: 6

sameerkn
sameerkn

Reputation: 2259

From Complexity point of view:

int x = int(i/j) means x > 0 only when i >= j. So you can avoid many unnecessary additions and divisions.

That is, if Matrix[i][j] = int(i/j); then Matrix[i][j] = 0; for (i < j)

Therefore, the for loops should be:

for i=1 to N-1
    for j=1 to i
        sum += Matrix[i][j];

UPDATE 1: After OP upated the question with sample output, it seems that the for loop for i should run till N. Modified Code as follow:

for(i = 1; i <= N; ++i)
    for(j = 1; j <= i; ++j)
        sum += (int)(i/j);

Upvotes: 1

George Sovetov
George Sovetov

Reputation: 5238

First column is 1, 2, 3, 4, 5, ....
Second column is 0, 1, 1, 2, 2, 3, 3, 4, 4, ....
Third columns is 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, ....

Then derive formula to calculate sum of column without loop in O(1) using arithmetic progression sum formula and accurately calculating what is at the beginning and the end of each column. Then iterate over columns. This will give you O(n) solution which fits given constraints.

Upvotes: 1

Related Questions