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

时间:2019-01-08 09:24:11

标签: c++ algorithm time-complexity

我试图在给定范围a,b a <= b中找到c的所有除数之和。

我尝试从ab循环并求和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;

2 个答案:

答案 0 :(得分:3)

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

这很简单。

  • 找到from,使from % c == 0 && from >= a的最小值
  • 找到to,使to % c == 0 && to <= 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 > 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';

答案 1 :(得分: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;