有效数字-适当除数的算术平均值不大于该数字的根

时间:2018-09-19 05:59:10

标签: java algorithm

任务似乎很容易-输入时,我得到测试数量(numOfTests),然后是两个数字(downBorderupBorder),我必须找出这些数字之间的多少数字(downBorderupBorder)是有效数字,其中有效数字是适当除数(除以一个和相同数字的所有除数)的算术平均值小于或等于该数字平方根的数字。 我写了代码,也许可以用,但是太慢了。 我的代码:

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

2 个答案:

答案 0 :(得分:1)

您可以将循环的复杂度从O(number)降低到O(sqrt(number))

这是基于以下观察结果:如果numberi整除,那么它也可以被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}}。