问题描述
我已经这样做了:-
int divisors(int div,int i) {
int ans = 0;
for (int j = 1; j * j <= div; j++) {
if (div % j == 0) {
if (div / j == j && j < i)ans++;
else {
if (j < i && div / j < i) {
ans += 2;
}
else if (j < i) {
ans += 1;
}
else {
break;
}
}
}
}
return ans;
}
但是这需要 O(sqrt(div)) 时间,我有办法优化它吗?
解决方法
你还没有说你会用这个函数做什么。如果您打算仅计算几个数字的除数数(小于限制),那么使用您提供的函数的方法很可能是最好的方法。
另一方面,如果您想为所有数字(可能在某些限制之间)计算它,那么更好的方法可能是像 Aritosthenes 的筛子一样计算它。也就是说,您遍历范围内的除数 d,对于每个 d,在 d、2d、...的计数上加 1,这些是唯一可以被 d 整除的数字。
所以有些东西
void compute( int maxn,int maxd,int* counts)
{ memset( counts,maxn *sizeof *counts);
for( int d=1; d<maxd; ++d)
{ for( int n=d; n<maxn; n+=d)
{ counts[n] += 1;
}
}
}
调用此后,counts[n] 将保存每个 n 0,..maxn-1 小于 maxd 的除数数。请注意,上面的代码中根本没有除法或取模运算;这些通常比其他算术运算慢得多。
,你不能低于O(sqrt(N))
,因为在最坏的情况下你需要k = N
,那个时候你必须遍历到sqrt(N)