【问题标题】:Sum of integer Division matrix整数除法矩阵之和
【发布时间】:2016-12-12 05:39:21
【问题描述】:

这是之前 HackerEarth Challenge 的一个问题 -

Roy 有一个大小为 NxN 的矩阵。行和列从 1 到 N 编号。 第 i 行的第 j 列包含整数除法 i/j。

换句话说,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

这是我对这个问题的解决方案

#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;
}

但是这个程序的输出不正确。

所以请告诉我我是否在这里正确地取得了成就。 如果是的话,我还能做些什么来优化这段代码。感谢您的帮助。

【问题讨论】:

  • 不应该int temp = N*i/j;int temp = i/j;
  • 即使你的答案是正确的,你的代码也有O(n^2) 的复杂性。对于这些在线法官网站来说,这几乎总是不合格的。
  • 感谢@PaulMcKenzie 的建议。你能建议我如何减少/通过哪种方法来减少这个程序的复杂性。
  • @user216112,对于初学者,i/jj &gt; i 时为零。因此,内部循环可以是for (j = 1; j &lt;= i; ++j )
  • 进一步优化:有N-1i/j等于1。因此,您可以使用for ( j = 1; j &lt; i; ++j ) 并将N - 1 添加到答案中。

标签: c++ algorithm matrix


【解决方案1】:

请注意,int(i/j) 对于较大的 j 值变化不大

即如果j = 1000 int(i/j) 对于1-1000 将是0,那么对于1000-2000 它将是1,依此类推。使用这一事实,您可以创建复杂度低得多的算法。

例如如果N = 50000,那么对于j = 1000,你将得到0... (1000)times + 1 ..(1000)times + 2..(1000)times....直到49,000/1000... (1000)times。

div = N/jans += (div *(div-1) *j)

如果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;
}

这是 O(n) 复杂度。

编辑:已更正以修复预期结果。

【讨论】:

  • 通过去掉不必要的操作和嵌套循环,这看起来像是很好的优化
  • 编译器不接受程序工作。根据系统如果输入为 2 2 4 预期正确输出应为 4 17
  • @user216112 基本思想是将矩阵展平为一维,并找到一个公式来计算总和。您知道样本数据是什么以及该站点声称的正确答案是什么。这个问题的设计是为了让你可以看到模式,而不是天真地写一个嵌套循环。
  • 上述函数在提供输入 N=2 时导致 Sum =2 而不是 4。
  • @RishiKesh,你能帮我把这些 o(n^2) 问题破解成 0(n),我只需要知道你是如何解决这个问题的。如果有任何参考,请给我。我想详细研究一下。提前致谢。
【解决方案2】:

第一列是1, 2, 3, 4, 5, ...
第二列是0, 1, 1, 2, 2, 3, 3, 4, 4, ...
第三列是0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, ...

然后使用算术级数求和公式导出公式以计算O(1)中无循环列的总和,并准确计算每列的开头和结尾。 然后遍历列。这将为您提供适合给定约束的 O(n) 解决方案。

【讨论】:

  • 谢谢,能不能提供一些通用方程来解决这个问题。
【解决方案3】:

从复杂性的角度来看:

int x = int(i/j) 仅在 i &gt;= j 时表示 x &gt; 0。这样可以避免很多不必要的加法和除法。

if Matrix[i][j] = int(i/j); then Matrix[i][j] = 0; for (i &lt; j)

因此,for 循环应该是:

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

更新 1:在 OP 使用示例输出更新问题后,ifor loop 似乎应该运行到 N。修改代码如下:

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

【讨论】:

  • 我已经用一些示例输出编辑了这个问题,但我仍然无法达到所需的结果。请帮帮我。
  • @user216112:您是否修改了帖子中提到的代码。您的代码中有 2 个问题。 [1] for 循环应该直到 N 而不是直到 &lt; N-1。 [2] int temp = N*i/j; 应该是 int temp = i/j;
【解决方案4】:

注意for-loop 条件

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

应该是

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

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

但不是for(int i=1;i &lt; N-1;i++)(该选项会丢失最后一项)。

接下来,像i/j 这样带有整数的表达式是整数除法,它只有结果的整数部分(没有四舍五入)。如果i &lt; j,这将导致0 值。

最后一个,总结表达式应该是(来自sum += Matrix[i][j])为

ans += Matrix[i][j];

但是你的矩阵在哪里?

更新

如果出于同样的原因,您使用表达式 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;
}

同时你应该明白long long不能在N &gt; 1000000时让你免于算术溢出

更新 2:

检查有关1 ≤ i, j ≤ N 的任务,如果真的是for as

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

【讨论】:

  • Matrix 从输入框中获取输入,在站点中他们可以选择这样做。
  • 我找不到区别,ans += N * i / j is int temp = N*i/j; ans = ans + temp;
  • 如果您需要尊重 - int temp = N*i/j; 需要更多 sizeof(int) 字节
  • 谢谢,我也是这么想的,为了更清楚,我把拆分(想在 stackflow 中提问)设置为一样。
  • 编译器不接受程序工作。根据系统如果输入为 2 2 4 预期正确输出应为 4 17
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-03
  • 1970-01-01
  • 1970-01-01
  • 2017-07-08
  • 2011-11-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多