如何有效地获得给定范围内的除数之和?

Posted

技术标签:

【中文标题】如何有效地获得给定范围内的除数之和?【英文标题】:How to get the sum of divisors in a given range efficiently? 【发布时间】:2019-01-08 09:24:10 【问题描述】:

我正在尝试在给定范围 a、b a c 的所有除数的总和。

我尝试从a 循环到b 并将c 的所有除数相加,但这似乎效率低下,因为a 和b 之间的绝对差可以是10^9。 有没有办法降低这种方法的时间复杂度?

int a, b, c;
cin >> a >> b >> c;
long long sum = 0;
for (int i = a; i <= b; i++) 
    if (i % c == 0) 
       ans += i;
    

cout << sum << endl;

【问题讨论】:

您可以尝试找到c 的素因数分解,然后从中导出所有可能的除数(在[a, b] 范围内)。不过,这要复杂得多。 ...并且您需要考虑可能的重复项(例如,如果您将任何因子与任何其他因子配对,则 4 将出现多次,且素数分解为 2、2、2)。 @Aconcagua “工作”是一个主观形容词,如果您没有指定接受标准。在这里,OP 明确指出他们的实现不够高效:然后需要更正。这是正题。如果你不确定,你可以在Meta Stack Overflow问。 【参考方案1】:

注意:这个问题不清楚我们是需要对除数求和(在描述中)还是整除整数(在代码示例中)。答案总结了可分割的项目。

这很简单。

找到from,即满足from % c == 0 &amp;&amp; from &gt;= a 的最小值 找到to,最大的值使得to % c == 0 &amp;&amp; to &lt;= b

.

 int n = (to - from) / c + 1;
 return n * (to + from) / 2;

返回to - from + c。当to 可能溢出您的类型而from 可能下溢时,请注意边界条件。

要找到from,请执行以下操作:

if (c < 0) c *= -1;  // works unless c == MIN_INT
if (a % c == 0)
   from = a;
else if (a >= 0)
   from = (a / c * c) + c
else 
   from = a / c * c;

to 类似,但考虑到我们需要向下取整,而不是向上取整。

另外,a &gt; b的情况需要单独处理。

编辑

这是没有循环、递归或容器的完整代码。它在 O(1) 中运行:

int a, b, c;
std::cin >> a >> b >> c;
if (!std::cin) 
   std::cout << "input error\n";
   return 0;


if (c < 0) c*= -1;
const int from = [a,c] 

   // no rounding needed
   if (a % c == 0) return a;

   // division rounds down to zero
   if (a > 0) return (1 + a / c) * c;

   // division rounds up to zero
   return a / c * c;
();

const int to = [b,c] 

   // no rounding needed
   if (b % c == 0) return b;

   // division rounds down to zero
   if (b > 0) return (b / c) * c;

   // division rounds up to zero
   return (b / c - 1) * c;
();

int64_t sum = 0;
if (from <= to)

 const int n = (to - from) / c + 1;
 sum = n * (to + from) / 2;

std::cout << sum << '\n';

【讨论】:

你确定不缺乘法吗? c = 6, a = 5, b = 30 -> from = 6, to = 30 -> to-from+c = 30-6+6 = 30;可除数:6、12、18、24、30,总和为 90。 @Aconcagua 已修复【参考方案2】:

首先找出所有作为 c 的除数的素数。这将为您留下一个数字列表 [w,x,y,z...]。然后在这个列表中保留一个包含所有整数倍数的哈希表集合,这些整数也是除数。

int a, b, c;
cin >> a >> b >> c;
long long sum = 0;

std::vector<int> all_prime_factors = // Get all prime factors of c
std::unordered_set<int> factorSet;
for (int primefactor : all_prime_factors)

    int factor = primefactor;
    while (factor <= b)
    
        if (factor % c == 0)
            factorSet.insert(factor);
        factor += primefactor;
    


for (int x : factorSet)

    sum += x;


cout << sum << endl;

【讨论】:

你能不能再快点?首先,将任何素因子添加到集合中,然后添加两个素因子的任何乘积,然后添加 3 中的任何一个,然后......当然,这不是微不足道的 - 然后获得素因子不同:虽然原始方法更愿意避免重复,这个需要重复保留... 为什么 a=12, b=18, c=6 会打印 12?不管我如何解释这个问题,这个结果对我来说毫无意义 假设使用factor += primefactor 进行修复,这在 O((b-a) * log(c) / log(log c) 中运行。这比 O(1) 的替代实现慢得多。

以上是关于如何有效地获得给定范围内的除数之和?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 获得“第二个命令行参数”

SQL如何从给定郊区5KM范围内的给定多个郊区中选择属性?

获得两个双精度数组绝对差之和的有效方法

给定'getrand100()'函数获取特定范围内的随机数

如何获得每小时范围内的交易次数

如何获得“选择案例以测试范围内的每个单元格?