任务似乎很容易-输入时,我得到测试数量(numOfTests
),然后是两个数字(downBorder
,upBorder
),我必须找出这些数字之间的多少数字(downBorder
,upBorder
)是有效数字,其中有效数字是适当除数(除以一个和相同数字的所有除数)的算术平均值小于或等于该数字平方根的数字。
我写了代码,也许可以用,但是太慢了。
我的代码:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws java.lang.Exception
{
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in)); //faster than Scanner
int numOfTests = Integer.parseInt(bf.readLine());
for(int i = 0; i < numOfTests; i++)
{
String[] borders = bf.readLine().split(" ");
long downBorder = Long.parseLong(borders[0]);
long upBorder = Long.parseLong(borders[1]);
//System.out.println(String.format("down: %s, up: %s", downBorder, upBorder));
System.out.println(countNumberOfSignificantNumbers(downBorder, upBorder));
}
}
/**
* print numbers of significant numbers - (arithmetic average of all divisors that is not bigger than root of that number)
* e.g 4 is significant but 6 is not
* @param downBorder
* @param upBorder
*/
private static int countNumberOfSignificantNumbers(Long downBorder, Long upBorder) {
int numberOfSignificantNumbers = 0;
for(Long i = downBorder; i <= upBorder; i++)
{
if(i%2 != 0)
continue;
else
{
double avgOfProperDivisors = getAvgArithOfSumOfNumberDividers(i);
if(avgOfProperDivisors != 0 && avgOfProperDivisors <= Math.sqrt(i))
numberOfSignificantNumbers++;
}
}
return numberOfSignificantNumbers;
}
/**
* method returns the arithemtic average of all proper divisors (all divisors except one and number itself)
* @param number
* @return
*/
public static double getAvgArithOfSumOfNumberDividers(Long number)
{
long maxD = number/2;
long sum=0;
long numOfDivs = 0;
for(long i = 2; i <= maxD; i++)
{
if(number % i == 0)
{
numOfDivs++;
sum += i;
}
}
return (numOfDivs > 0) ? (double)sum/numOfDivs : 0;
}
}
此任务的瓶颈是计算除数的平均值。如何使它变得更好更快?
Example input:
2
4 6
1 3
Example output:
1
0
答案 0 :(得分:1)
您可以将循环的复杂度从O(number)
降低到O(sqrt(number))
。
这是基于以下观察结果:如果number
被i
整除,那么它也可以被number/i
整除。鉴于此,您可以一次计算两个除数。鉴于除数的稀疏度随着数量的增加而增加(即在找到除数之前必须检查的数字数量),因此您可以通过这种方式节省大量工作。
例如:
for (long i = 2; i*i <= n; ++i) {
if (n % i == 0) {
// i is a divisor, so increment the counters.
numOfDivs++; sum += i;
long c = n / i;
if (c != i) {
// c is a distinct divisor from i, so also increment the counters.
numOfDivs++; sum += c;
}
}
}
例如10 = 5 * 2。当i = 2时,该方法找到一个除数,这意味着c = 5。 i = 3后可以停止检查。相反,在i<=10/2
期间进行检查将在i = 5之后停止检查。
随着数量的增加,差异变得更大。例如,使用number==1000
时,您用i<=1000/2
来检查499个数字,而使用i*i <= 1000
时只检查30个。
答案 1 :(得分:1)
有效数字将始终是质数的理想平方,例如4、9、25、49、121等。您需要检查的是upBorder
和{之间有多少个质数理想平方。 {1}}。