如何求和序列?
Posted
技术标签:
【中文标题】如何求和序列?【英文标题】:How to sum sequence? 【发布时间】:2015-01-04 18:04:39 【问题描述】:我如何总结以下序列:
⌊n/1⌋ + ⌊n/2⌋ + ⌊n/3⌋ + ... + ⌊n/n⌋
这只是 C++ 上的 O(n) 解决方案:
#include <iostream>
int main()
int n;
std::cin>>n;
unsigned long long res=0;
for (int i=1;i<=n;i++)
res+= n/i;
std::cout<<res<<std::endl;
return 0;
你知道比这更好的解决方案吗?我的意思是 O(1) 或 O(log(n))。感谢您的宝贵时间:) 和解决方案
编辑: 感谢您的所有回答。如果有人想要解决方案 O(sqrt(n)): 蟒蛇:
import math
def seq_sum(n):
sqrtn = int(math.sqrt(n))
return sum(n // k for k in range(1, sqrtn + 1)) * 2 - sqrtn ** 2
n = int(input())
print(seq_sum(n))
C++:
#include <iostream>
#include <cmath>
int main()
int n;
std::cin>>n;
int sqrtn = (int)(std::sqrt(n));
long long res2 = 0;
for (int i=1;i<=sqrtn;i++)
res2 +=2*(n/i);
res2 -= sqrtn*sqrtn;
std::cout<<res2<<std::endl;
return 0;
【问题讨论】:
O(sqrt(n))
好吗?
@ILoveCoding:即使不是 O(1),也可以随意发布它作为答案。如果它是正确的,我会赞成。
这似乎与O(1)
解决方案非常相关:math.stackexchange.com/questions/740442/…
参见A006218 中的参考资料,其中提到了 O(n^1/3) 算法。
【参考方案1】:
这是Dirichlet's divisor summatory function D(x)。使用以下公式 (source)
在哪里
提供以下 O(sqrt(n))
伪代码(恰好是有效的 Python):
def seq_sum(n):
sqrtn = int(math.sqrt(n))
return sum(n // k for k in range(1, sqrtn + 1)) * 2 - sqrtn ** 2
注意事项:
Python 中的//
运算符是整数,即截断、除法。
math.sqrt()
用作说明。严格来说,这应该使用 exact integer square root algorithm 而不是浮点数学。
【讨论】:
我不是反对者,但您的伪代码不应该像u = floor(sqrt(x))
那样涉及楼层函数,与x/k
相同。另外我认为这估计了系列的总和,而不是给出确切的总和。
@doc:Python 中的//
运算符是整数(截断)除法。
@doc:只要整数平方根准确,它就会给出准确的总和。
@NPE 啊,那好吧。不错。【参考方案2】:
取自Divisor summatory function上的***文章,
在哪里。那应该提供 时间解决方案。
编辑:整数平方根问题也可以在平方根甚至对数时间内解决 - 以防万一不明显。
【讨论】:
【参考方案3】:Polymath 项目概述了一种用于在 O(n^(1/3 + o(1))) 时间内计算此函数的算法,请参阅第 8-9 页的第 2.1 节:
http://arxiv.org/abs/1009.3956
该算法涉及将区域切成足够细的间隔并估计每个间隔的值,其中间隔选择得足够细,以便在四舍五入到最接近的整数时估计将是准确的。因此,您可以直接计算到某个范围(他们建议 100n^(1/3),但您可以谨慎修改),然后在这些薄片中完成其余部分。
有关此序列的更多信息,请参阅the OEIS entry。
编辑:我现在看到 Kerrek SB 在 cmets 中提到了这个算法。不过,公平地说,我在 5 年前在 OEIS 中添加了评论,所以我不会因为发布“他的”答案而感到难过。 :)
我还应该提到,没有 O(1) 算法是可能的,因为答案在 n log n 左右,因此即使 把它写出来也需要时间 > log n。
【讨论】:
抱歉,我找不到第 2.1 节。你可以帮帮我吗? :-) @vasylysk:从第 8 页底部开始,一直到第 9 页末尾。【参考方案4】:让我们将所有数字1, 2, 3, ..., n
分成两组:小于或等于sqrt(n)
和大于sqrt(n)
。对于第一组,我们可以通过简单的迭代来计算总和。对于第二组,我们可以使用以下观察:如果a > sqrt(n)
,比n / a < sqrt(n)
。这就是为什么我们可以迭代[n / i] = d
的值(从1
到sqrt(n)
)并计算i
和[n / i] = d
的数量。它可以在O(1)
中找到固定的d
,使用[n / i] = d
表示i * d <= n and i * (d + 1) > n
的事实,它给出[n / (d + 1)] < i <= [n / d]
。
第一组和第二组在O(sqrt(n))
中处理,总共给O(sqrt(n))
时间。
【讨论】:
【参考方案5】:对于较大的n
,使用公式:
在哪里
( 是超越数。)
有关详细信息,请参阅Euler-Mascheroni constant 文章。
【讨论】:
这是否考虑到每个术语的四舍五入? (顺便说一句,我没有投反对票。) 是的,因为目的是在第二个等号之后使用封闭形式,而不是循环遍历每个分数。 不清楚为什么这个答案有问题,投反对票的人应该评论他们为什么这样做 @asimes:我没有投反对票,但对于初学者来说,它不会返回整数,而显然问题中的序列加起来是一个整数。 哇,我没有考虑地板。对不起。你说的对。我应该注意到每个分数周围的地板运算符。【参考方案6】:您可以注意到集合 S = ⌊n/1⌋, ⌊n/2⌋, ..., ⌊n/(n-1) 中有 O(n^(1/2)) 个唯一值)⌋,⌊n/n⌋。因此,您可以计算 O(n^(1/2))
中的函数此外,由于该函数是不对称的,您甚至可以使用以下公式更快地计算 x2:D(n) = Σ(x=1->u)(⌊n/x⌋) - u^2 for u = ⌊ n^(1/2)⌋
更复杂但更快:使用 Richard Sladkey 在this paper 中描述的方法,您可以计算 O(n^(1/3)) 中的函数
【讨论】:
请在您的回答中提供更多详细信息。正如目前所写的那样,很难理解您的解决方案。以上是关于如何求和序列?的主要内容,如果未能解决你的问题,请参考以下文章