一、题目

(1)资源限制

内存限制:512.0MB
C/C++时间限制:1.0s
Java时间限制:3.0s
Python时间限制:5.0s

(2)输入

输入一个正整数N

(3)输出

N有几个约数

(4)样例输入

12

(5)样例输出

6

(6)样例说明

12的约数包括:1,2,3,4,6,12。共6个

二、原理与分析

(1)求约数的公式
(a1+1)*(a2+1)*(a3+1)*...*(ak+1)
(2)公式推理
  • 任意一个数均可表示为以下形式(即分解质因数):
N=p1^a1*p2^a2*p3^a3*...*pk^ak
  • 例如:
24 = 2^3*3^1 即p1=1,a1=0,p2=2,a2=3,p3=3,a3=1,p4=4,a4=0...
  • 同样任意一个数的约数就可以表示为以下形式:
p1^b1,p2^b2,p3^b3*,...,pk^bk
  • 我们可知从b1到bk的每一种取法,都对应着N的一个不同的约数
    b1有[0,a1]种选法,即a1+1种选法

    bk有[0,ak]种选法,即ak+1种选法
  • 相乘可得
一共有(a1+1)*(a2+1)*(a3+1)*...*(ak+1)种选法,每种选法对应一个约数
  • 求约数个数的问题被转化为了求从b1到bk的选法
即约数的个数 = (a1+1)*(a2+1)*(a3+1)*...*(ak+1)
(3)举例分析
  • 例如:对180分解质因数可得
180 = (2^2)*(3^2)*(5^1)
  • 根据公式可得约数个数为
(a1+1)*(a2+1)*(a3+1)*...*(ak+1)=(2+1)*(2+1)*(1+1)=18个
  • 从根本上来说:
180 = (2^2)*(3^2)*(5^1)

以2为底,指数可以选择0,1,2,三种选法
以3为底,指数可以选择0,1,2,三种选法
以5为底,指数可以选择0,1,两种选法
那么约数一共就有

3*3*2=18种选法
(4)小知识
  • int范围内的整数,约数个数最多的大概是1500个,有时可以用来快速验证答案
(5)HashMap
  • 由于每一个p1和b1都是一一对应的,即底数和指数时一一对应的,我们可以用HashMap来存储
  • 因此需要了解Map集合的相关知识:
    Map集合是一种双列集合,每个元素包含两个数据。
    Map集合的每个元素的格式:key=value(键值对元素)。
    Map集合也被称为”键值对集合“
    键和值一一对应,一个键对应一个值,整个集合的特点是由键决定的
    HashMap:元素按照键是无序,不重复,无索引,值不做要求。(与Map体系一致)
    getOrDefault(key, default):如果存在key, 则返回其对应的value, 否则返回给定的默认值


三、代码

import java.util.*;

public class Main {
    //定义一个HashMap来对应存储所有项的底数与指数,一一对应,方便使用
    public static HashMap<Integer, Integer> primes = new HashMap<>();
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int x = sc.nextInt();
        //每个合数都可以写成几个质数相乘的形式,这几个质数就都叫做这个合数的质因数
        //此处用到的就是分解质因数的算法
        //用i遍历x的底数,若i为x的底数(即x%i==0),就把i对应的指数加一,即把map的value值加一
        //例如8=2^3,那么map中key为2的value值就一共会加3
        for (int i = 2; i <= x/i; i++) {
            while (x % i == 0){
                x = x/i;
                //getOrDefault(key, default)如果存在key, 则返回其对应的value, 否则返回给定的默认值
                //这一句用getOrDefault是防止NullPointerException
                primes.put(i, primes.getOrDefault(i, 0) + 1);
            }
        }
        //如果说x被所有小于根号x的质数因子除完后,还大于1,说明剩下的一定是那个大于根号x的质因子,直接输出即可 (例如11,43这样的数)
        //证明:一个数x中最多包含一个大于根号x的质数因子,很好证明,如果有两个大于根号x的质数因子那么这俩相乘就大于x了,反证法成立
        if (x > 1){
            primes.put(x, primes.getOrDefault(x, 0) + 1);
        }
        //result存储最终结果
        long result = 1;
        //用i遍历每一个指数
        //利用求约数个数的公式:(a1+1)*(a2+1)*(a3+1)*...*(ak+1)
        for (Integer i:primes.values()) {
            result = (result * (i + 1));
        }
        System.out.println(result);
    }
}

去注释版

import java.util.*;

public class Main {
    public static HashMap<Integer, Integer> primes = new HashMap<>();
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int x = sc.nextInt();
        for (int i = 2; i <= x/i; i++) {
            while (x % i == 0){
                x = x/i;
                primes.put(i, primes.getOrDefault(i, 0) + 1);
            }
        }
        if (x > 1){
            primes.put(x, primes.getOrDefault(x, 0) + 1);
        }
        long result = 1;
        for (Integer i:primes.values()) {
            result = (result * (i + 1));
        }
        System.out.println(result);
    }
}