假设我们3
号码N
,x
和y
始终为>=1
。
N将大于x
且y
且x
将大于y
。
现在我们需要找到1到N之间所有数字的总和,它们可以被x或y 整除。
我想出了这个:
sum = 0;
for(i=1;i<=N;i++)
{
if(i%x || i%y)
sum += i;
}
有没有更好的方法来找到避免for循环的总和?
我现在已经好好打了好几天但是没有更好的东西。
如果N
的值有上限,我们可以使用查找方法来加速该过程。
谢谢大家。
我想要一个基于C / C ++的解决方案。是否有内置函数来执行此操作?或者我必须编写算法代码?
答案 0 :(得分:27)
是。你可以完全取消for循环,并在恒定时间内找到总和。
根据Inclusion–exclusion principle总结x
的倍数和y
的倍数,并减去已添加两次的常见倍数应该给出我们所需的金额。
Required Sum = sum of ( multiples of x that are <= N ) +
sum of ( multiples of y that are <= N ) -
sum of ( multiples of (x*y) that are <= N )
示例:
N = 15
x = 3
y = 4
Required sum = ( 3 + 6 + 9 + 12 + 15) + // multiples of 3
( 4 + 8 + 12 ) - // multiples of 4
( 12 ) // multiples of 12
如上所示,我们不得不减去12
,因为它是一个常见的倍数。
整个算法O(1)如何?
令sum(x, N)
为x
的倍数之和,其小于或等于N
。
sum(x,N) = x + 2x + ... + floor(N/x) * x
= x * ( 1 + 2 + ... + floor(N/x) )
= x * ( 1 + 2 + ... + k) // Where k = floor(N/x)
= x * k * (k+1) / 2 // Sum of first k natural num = k*(k+1)/2
现在可以在恒定时间内计算k = floor(N/x)
。
知道k
后sum(x,N)
可以在固定时间内计算。
因此,所需的总和也可以在恒定时间内计算。
修改强>
仅当x
和y
为co-primes时,上述讨论才适用。如果不是,我们需要使用LCM(x,y)
代替x*y
。有许多方法可以找到LCM,其中一种方法是通过GCD划分产品。现在GCD不能在恒定时间内计算,但其time complexity可以显着小于线性时间。
答案 1 :(得分:4)
如果一个数字可被X整除,则它必须是x的倍数。 如果一个数字可被Y整除,则它必须是y的倍数。
我相信,如果你对x和y的所有倍数进行for循环,并避免重复,你应该得到相同的答案。
从我的脑海中,出现了类似的东西:
sum = 0
for( i=x; i<=n; i+=x)
sum += i;
for( i=y; i<=n; i+=y)
if( y % x != 0 )
sum += i;