c++ - 求和的速度问题(除数之和)
问题描述
我应该在 C++ 中实现这个求和。我已经尝试过使用这段代码,但是对于高达 10 ^ 12 的数字来说,它需要的时间太长了。
总结是:
对于任何正整数 k,令 d(k) 表示 k 的正除数的数量(包括 1 和 k 本身)。例如,对于数字 4:1 有 1 个除数,2 有两个除数,3 有两个除数,4 有三个除数。所以结果是 8。
这是我的代码:
#include <iostream>
#include <algorithm>
using namespace std;
int findDivisors(long long n)
{
int c=0;
for(int j=1;j*j<=n;j++)
{
if(n%j==0)
{
c++;
if(j!=(n/j))
{
c++;
}
}
}
return c;
}
long long compute(long long n)
{
long long sum=0;
for(int i=1; i<=n; i++)
{
sum += (findDivisors(i));
}
return sum;
}
int main()
{
int n, divisors;
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
cin >> n;
cout << compute(n);
}
我认为这不仅仅是一个简单的优化问题,也许我应该完全改变算法。有人有什么想法可以加快速度吗?谢谢你。
解决方案
我使用您的蛮力方法作为参考来拥有测试用例。我用的是
compute(12) == 35
cpmpute(100) == 482
不要对计算分解感到困惑。在分解数字时可以玩一些技巧,但实际上你不需要任何技巧。解决方案是一个简单的O(N)
循环:
#include <iostream>
#include <limits>
long long compute(long long n){
long long sum = n+1;
for (long long i=2; i < n ; ++i){
sum += n/i;
}
return sum;
}
int main()
{
std::cout << compute(12) << "\n";
std::cout << compute(100) << "\n";
}
输出:
35
482
为什么这行得通?
关键在于 Marc Glisse 的评论:
与这类问题一样,这个总和实际上计算对 x, y,其中 x 除以 y,并且总和被安排为首先计算与固定 y 相对应的所有 x,但没有什么说你必须保持这种方式。
我可以在这里停下来,因为评论已经解释了一切。不过,如果它还没有点击...
诀窍是要意识到计算所有数字的除数要简单得多,n
而不是n
计算单个数字的除数并求和。
您无需关心 eg 的因式分解123123123
或52323423
将所有除数计数为10000000000
. 你所需要的只是改变观点。与其尝试分解数字,不如考虑除数。除数多久1
出现一次n
?很简单:-n
次。除数多久2
出现一次?仍然很简单:n/2
次,因为每一秒的数字都可以被 整除2
。除数3
?每第三个数都可以被 整除3
。我希望你已经可以看到模式了。
您甚至可以将循环减少到只循环 until n/2
,因为更大的数字显然只作为除数出现一次。虽然我没有费心去更进一步,因为最大的变化是从你的O(N * sqrt(N))
到O(N)
.
推荐阅读
- python - 每批更新损失值以获得平均历元损失
- namedtuple - 更新 NamedTuple 中的字段(通过键入)
- javascript - 如何使用javascript删除数组中甚至没有再次出现的元素?
- git - Visual Code Studio 和 Github:我的新分支没有考虑我的更改
- angular - 在 Angular 中,我应该在哪里存储用户对象,以便在导航设置中引用它以获取可用性?
- javascript - 使用 Context API 与 CloneElement 为直接后代传递道具
- android - 添加evernote库得到Manifest merge failed com.android.support:support-compat:28.0.0
- apache-kafka - Confluent - 如何使用外部 Zookeeper 而不是嵌入式 Zookeeper
- swift - Swift - 线程 1:致命错误:索引超出范围错误问题
- mysql - GROUP BY 仅当列不为空/空时