以下是HackerEarth挑战赛中的一个问题 -
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;
}
但是这个程序的输出结果不正确。
所以请告诉我,如果我在这里做得对。 如果是,我还可以做些什么来优化此代码。谢谢你的帮助。
答案 0 :(得分:6)
请注意,对于int(i/j)
j
不会发生太大变化
即。如果j = 1000
的{{1}} int(i/j)
为0
,则1-1000
为1
,依此类推。使用这个事实,您可以创建一个复杂度更低的算法。
e.g。如果是1000-2000
,那么对于N = 50000
,您将获得j = 1000
次+ 0... (1000)
次+ 1 ..(1000)
次......最多2..(1000)
次。
即。 49,000/1000... (1000)
div = N/j
如果ans += (div *(div-1) *j)
不是整数,您还需要进行更正,如下面的代码所示。
N/j
这是O(n)的复杂性。
编辑:更正以修复预期结果。
答案 1 :(得分:1)
注意for
- 循环条件
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 < N-1;i++)
(该选项会丢失最后一项)。
接下来,像i/j
这样的带整数的表达式是整数除法,它只有结果的整数部分(没有舍入)。如果0
,则会产生i < j
值。
最后一个,总结表达式应该是(从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 > 1000000
无法避免算术溢出
更新2:
检查有关1 ≤ i, j ≤ N
的任务,如果确实是&lt; = N,请尝试将for
更改为
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= i; j++)
{
ans += i / j;
}
}
答案 2 :(得分:1)
从复杂性的角度来看:
int x = int(i/j)
仅在x > 0
时表示i >= j
。因此,您可以避免许多不必要的添加和划分。
即if Matrix[i][j] = int(i/j); then Matrix[i][j] = 0; for (i < j)
因此,for
循环应为:
for i=1 to N-1
for j=1 to i
sum += Matrix[i][j];
更新1: OP上传了带有示例输出的问题后,for loop
的{{1}}似乎应该运行到i
。修改后的代码如下:
N
答案 3 :(得分:1)
第一栏是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)解决方案。