我正在尝试解决Project Euler problem 401。他们唯一能找到解决方法的方法就是蛮力。我已经运行这个代码10分钟没有任何答案。任何人都可以帮助我改进它的想法。
代码:
#include <iostream>
#include <cmath>
#define ull unsigned long long
using namespace std;
ull sigma2(ull n);
ull SIGMA2(ull n);
int main()
{
ull ans = SIGMA2(1000000000000000) % 1000000000;
cout << "Answer: " << ans << endl;
cin.get();
cin.ignore();
return 0;
}
ull sigma2(ull n)
{
ull sum = 0;
for(ull i = 1; i<=floor(sqrt(n)); i++)
{
if(n%i == 0)
{
sum += (i*i)+((n/i)*(n/i));
}
if(i*i == n)
{
sum -= n;
}
}
return sum;
}
ull SIGMA2(ull n)
{
ull sum = 0;
for(ull i = 1; i<=n; i++)
{
sum+=sigma2(i);
}
return sum;
}
答案 0 :(得分:3)
你错过了一些分隔符,如果a / b = c,b
是a
的分隔符,那么c
也会是a
的分隔符但是c
可能大于floor(sqrt(a))
,例如3&gt; (sqrt(6))但是除以6。
然后你应该把你的楼层(sqrt(n))放在一个变量中并使用for中的变量,否则你会重新计算每个非常昂贵的操作。
答案 1 :(得分:2)
您可以做一些简单的优化:
sigma2
,floor(sqrt(n))
(但编译器可能无论如何都要这样做),1
到n
预先计算所有整数的平方,然后使用数组查找而不是乘法通过改变方法,您将获得更多收益。想想你想要做的事情 - 将所有整数的除数从1到n求平方。您将除数除以它们的除法,但您可以在此总和中重新组合术语。让我们按其价值对除数进行分组:
1
对所有内容进行划分,以便在总和中显示n
次,总计1*1*n
,2
划分evens并显示n/2
(整数除法!)次,总计2*2*(n/2)
,k
...将带来k*k*(n/k)
总计。因此,我们应该将k*k*(n/k)
k
从1
加到n
。
答案 2 :(得分:1)
您可以执行的一项简单优化是,数字中会有许多重复因素。
所以首先估计一个因子中有多少个数(所有N个数)
在多少个数字中,2是一个因子(N / 2)
...
其他人也一样。
只需将它们的方块与它们的频率相乘。
然后,时间复杂度将直接减少到O(N)
答案 3 :(得分:1)
想想问题。
Bruteforce你尝试的方式显然不是一个好主意。
你应该想出更好的东西...... 是不是有任何方法如何使用一些很好的素数分解方法来加速计算?是不是有任何递归模式?试着找点什么......
答案 4 :(得分:0)
有明显的微优化,例如++ i而不是i ++或者从循环中获取楼层(sqrt(n))(这两个浮点运算与循环中的其他整数运算相比非常昂贵),并且仅使用一次n / i(对其使用虚拟变量,然后计算虚拟的平方)。
算法中也有相当明显的简化。例如,SIGMA2(i)= SIGMA2(i-1)+ sigma2(i)。但是不要使用递归,因为你需要一个非常庞大的数字,这将无法工作,你的堆栈内存将耗尽。使用循环而不是递归。有巨大的改进潜力。
而且,有一个更大的问题 - 10 ^ 15有15位数。这个数字的平方有30位数。没有办法你可以将它存储到unsigned long long中,我认为它有20个数字。所以你需要以某种方式使用模数10 ^ 9(赋值的结束)并为你的计算获得额外的空间......
当使用蛮力时,打印每个数百万个数字的临时结果,例如,让您知道您接近最终结果的速度有多快。盲目等待10分钟并不是一个好主意。