我已经给出了一个范围 L到R 。我必须找出L到R之间有多少个数字,以便数字具有奇数个除数。
1<L<R<10^18
由于L和R非常高,因此循环简单会导致超时
我发现二进制搜索可用于解决此问题。
我无法理解二元搜索如何帮助查找具有奇数的数字的数字除数。
代码:
int find (long long n) {
int low,high,mid;
long long v1,v2;
low = 1;
high = 1e9 + 1;
if (n == 0) {
return 0;
}
while (low <= high) {
mid = (low + high) / 2;
v1 = mid * 1LL * mid;
v2 = (mid + 1) * 1LL * (mid + 1);
if (v1 <= n) {
if (v2 > n) {
return mid;
} else {
low = mid + 1;
}
} else {
high = mid - 1;
}
}
}
和
答案:ans = find(r) - find(l - 1);
请在数论中解释二元搜索的概念
答案 0 :(得分:3)
该算法基于一个简单的事实,即为了得到奇数个除数,数n
必须是一个完整的正方形。否则,对于每个除数k
,还有另一个不同的除数n/k
,所以你总是会有偶数除数。此算法只计算1
和提供的n
(包括)之间的整数平方数,实际上是integer square root(floor(sqrt(n))
)。所以它使用二进制搜索找到平方根。如果您的平台/语言上的sqrt(n)
方法足够精确,您可以像这样解决问题:
ans = floor(sqrt(r)) - floor(sqrt(l-1));
通常double
类型没有提供足够的精度,因此结果可能少一个或多一个。可能这就是使用二进制搜索的原因。不过,你仍然可以使用sqrt
。只需计算之后的平方,如果需要,可以将结果调整为1(这样会快得多)。或者你可以使用牛顿方法(它会比调整时sqrt
慢,但比二分搜索快得多。)
答案 1 :(得分:0)
对于数字 N ,假设 d 是 N 的除数。然后总是有一个 N / d 的数字,它可以划分 N 。
只有在某些情况下d = (N/d)
实施例:
如果N = 16
如果除数d=1
则N/d = 16
如果除数d=2
则N/d = 8
如果除数d=4
则N/d = 4
所以,如果我们想知道 R 和 L 之间有奇数除数的数字,我们需要知道这个范围之间的平方数是多少
小于或等于R的平方数是 = square_root(R)
小于的平方数(以L为代表)L是 = square_root(L-1)
So answer = floor(square_root(R))-floor(square_root(L-1))
由于我们只需要整数部分,所以我们采取行动。