简体   繁体   English

整数除法矩阵之和

[英]Sum of integer Division matrix

Here is a question from previous HackerEarth Challenge - 这是上届HackerEarth挑战赛的一个问题-

Roy has a matrix of size NxN. 罗伊的矩阵大小为NxN。 Rows and Columns are numbered from 1 to N. jth column of ith row contains integer division i/j. 行和列的编号从1到N。第i行的第j列包含整数除法i / j。

In other words, Matrix[i][j] = int(i/j) where 1 ≤ i, j ≤ N. 换句话说,Matrix [i] [j] = int(i / j),其中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. 谢谢你的帮助。

在此处输入图片说明

Note that int(i/j) does not change much for larger values of j 请注意,对于较大的j值, int(i/j)不会有太大变化

ie if j = 1000 int(i/j) will be 0 for 1-1000 , then it will be 1 for 1000-2000 , and so on. 即,如果j = 1000 int(i/j)对于1-1000将为0 ,那么对于1000-2000将为1 ,依此类推。 Using this fact, you can create an algorithm with much lower complexity. 利用这一事实,您可以创建复杂度低得多的算法。

eg 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. 例如,如果N = 50000 ,则对于j = 1000 ,您将得到0... (1000)次+1 1 ..(1000)次+ 2..(1000)次......最高49,000/1000... (1000)次。

ie div = N/j ans += (div *(div-1) *j) 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. 如果N/j不是整数,则还需要进行更正,如下面的代码所示。

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. 这是O(n)的复杂性。

Edit: Corrected to fix expected results. 编辑:更正了预期的结果。

Pay attention on for -loop condition 在注重for -loop条件

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). 但不是for(int i=1;i < N-1;i++) (该选项丢失了最后一项)。

Next, expressions like i/j with integers are integer division that has only integer part of result (without rounding). 接下来,像i/j具有整数的表达式是整数除法 ,其结果的整数部分(不舍入)。 This will lead to 0 value if i < j . 如果i < j这将导致0值。

And the last one, summarizing expression should be (from sum += Matrix[i][j] ) as 最后一个总结表达式应为(from sum += Matrix[i][j] )如

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: 如果出于相同的原因,您使用表达式N*i/j代替矩阵( Matrix[i][j] )的值,并且出于防御性的考虑,希望使用整数算术 ,则可以将代码最小化为:

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 同时,您应该了解,当N > 1000000时, long long无法使您摆脱算术溢出

UPDATE 2: 更新2:

Check the task about 1 ≤ i, j ≤ N and if it is really <= N try changes for both for as 检查任务约1 ≤ i, j ≤ N如果是真的<= N尝试都变化for

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

From Complexity point of view: 从复杂性的角度来看:

int x = int(i/j) means x > 0 only when i >= j . int x = int(i/j)仅在i >= j时表示x > 0 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) 也就是说, if Matrix[i][j] = int(i/j); then Matrix[i][j] = 0; for (i < j) if Matrix[i][j] = int(i/j); then Matrix[i][j] = 0; for (i < j)

Therefore, the for loops should be: 因此, for循环应为:

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 . 更新1:OP更新过的样品与输出的问题后,似乎for loopi应该运行,直到N Modified Code as follow: 修改后的代码如下:

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

First column is 1, 2, 3, 4, 5, ... . 第一列是1, 2, 3, 4, 5, ...
Second column is 0, 1, 1, 2, 2, 3, 3, 4, 4, ... . 第二列是0, 1, 1, 2, 2, 3, 3, 4, 4, ...
Third columns is 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, ... . 第三列是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. 然后,使用算术级数求和公式导出公式,以计算O(1)中不带循环的列的总和,并准确计算每列的开始和结束处的值。 Then iterate over columns. 然后遍历列。 This will give you O(n) solution which fits given constraints. 这将为您提供适合给定约束的O(n)解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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