如何求和序列?

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 &gt; sqrt(n),比n / a &lt; sqrt(n)。这就是为什么我们可以迭代[n / i] = d 的值(从1sqrt(n))并计算i[n / i] = d 的数量。它可以在O(1) 中找到固定的d,使用[n / i] = d 表示i * d &lt;= n and i * (d + 1) &gt; n 的事实,它给出[n / (d + 1)] &lt; i &lt;= [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)) 中的函数

【讨论】:

请在您的回答中提供更多详细信息。正如目前所写的那样,很难理解您的解决方案。

以上是关于如何求和序列?的主要内容,如果未能解决你的问题,请参考以下文章

序列求和

子序列求和问题

对向量中的整数序列求和

序列求和蓝桥杯国赛

对时间戳略有差异的时间序列求和

最大子序列求和问题