如何有效地获得给定范围内的除数之和?
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 && 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';
【讨论】:
你确定不缺乘法吗? 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) 的替代实现慢得多。
以上是关于如何有效地获得给定范围内的除数之和?的主要内容,如果未能解决你的问题,请参考以下文章