给出两个数字M和N.令qi是i * N / M的整数部分。从0到M-1,qi的总和是多少。 O(M)是显而易见的方法。这可以在更短的时间内完成,如果存在一些更简单的简化表达式,可能是O(1)吗?
答案 0 :(得分:3)
有趣的问题。 (这篇文章会让我希望我们在SO上有数学格式......)
我的方法是将问题写成
∑i floor(i*N/M) = ∑i i*N/M - ∑i [i*N/M]
其中[]
是“小数部分”运算符(即[1.3] = 0.3,[6] = 0等)。
然后,前半部分很简单:它是一个正常的算术序列和乘以N/M
,因此它总和为N*(M-1)/2
。下半场比较棘手,但是你会明白为什么将它与上半场分开是至关重要的。
让k = gcd(N, M)
。然后,让n = N/k
和m = M/k
,让后半部分为∑i [i*n/m]
。至关重要的是,n
和m
现在相对来说是素数。 i
的总和从0
到M-1 = km-1
。我们可以将i
拆分为m
的倍数,将剩余部分拆分为i = qm + r
,以便总和现在
∑q ∑r [r*n/m]
其中q
总和从0
到k-1
和r
总和从0
到m-1
。现在是关键步骤:因为n
和m
是相对素数,r*n
的序列r = 0..m-1
是0, 1, 2, 3, ..., m-1
的{em>置换 } mod m 。因此,序列[r*n/m]
是0/m, 1/m, 2/m, ..., (m-1)/m
的排列,因此∑r [r*n/m] = ∑r r/m = m*(m-1)/2/m = (m-1)/2
。因此,整个总和折叠为k * (m-1)/2 = (km - k) / 2 = (M - k) / 2
。
最后,我们将两半结合起来:N*(M-1)/2 - (M-k)/2 = (NM - N - M + k)/2
。
因此,期望的总和是(NM - N - M + gcd(N, M))/2
。使用Euclid算法可以relatively quickly计算GCD,因此计算速度相当快。
答案 1 :(得分:0)
在我看来,你试图将0N / M + 1N / M + 2N / M + 3N / M ......(M-1)N / M加起来。如果是这样,你有(0 + 1 + 2 + 3 ... +(M-1))N / M.您可以在O(1)中解决这个问题,因为(0 + 1 + 2 + 3 + ... +(M-1))是M *(M-1)/ 2。 M取消,你得到(M-1)N / 2.