质因数分解是指将一个数分解成全由质数的X次方相乘的式子
设被质因子分解的数为:100
思路:for i = 1 to 100,如果i是合数(质数的反义词也可以说是非质数) 将被分解的数除以i并将i处的次方数+1
public static void simple(int n) {
int[] st = new int[n + 1];
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
while (n % i == 0) {
n /= i;
st[i]++;
}
}
}
// System.out.println(Arrays.toString(st));
}
st[]为记录次方数的数组,因为记录的都是质数+[如果不能被<n的任意质数能分解,那么自己就会在st[n]的位置+1]。
一行行来分析
for (int i = 2; i * i <= n; i++) {
// ...
}
这行代码其实是i <= Math.sqrt的变体,因为根号比平方要慢,所以写成这个样子,例如100可以分解成1 * 100, 2 * 50, 4 * 25, 10 * 10, 25 * 4, 50 * 2, 100 * 1。在10以后的等式其实都是10以前(包含10)的镜像翻转,比如2 * 50 和 50 * 2,那么其实1-100,我们只需要求前1-sqrt(100)就可以了,立方求因子也是这个思路 i * i 换成 i * i * i 就可以。
if (n % i == 0) {
// ...
}
如果当前数能够被整除,意思就是当前数如果不是质数,因为质数是不能被整除的
while (n % i == 0) {
n /= i;
st[i]++;
}
如果当前这个数可以被整除,那么就把它的约数一点点分解掉,比如说100 = 4 * 25 = 2 * 2 * 5 * 5,这个while的作用就是从小到大一点点把因数给剥离开。
我们可以在最后一行加一句输出,看看st数组最终是什么样子的
[0, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
可以看到2和5的位置是2 说明 100 = 22 x 52
我们再来看题目
定义阶乘 n! = 1 × 2 × 3 × · · · × nn!=1×2×3×⋅⋅⋅×n。
请问 100!100! (100100 的阶乘)有多少个正约数。
如果使用暴力解法,会算到考试结束都算不出来 这里需要引入唯一分解定力来求,直接使用蓝桥杯决赛训练营的图(侵删)
上面已经了解了质因数分解,我们只需要从小到大求出每个质数的次方即可
将100!分解为: 1 * 2 * 3 * 4 * 5 。。。 * 100
int[] st = new int[101];
for (int j = 1; j <= 100; j++) { // 从1到100
int k = j; // 不能让分解结果影响循环
for (int i = 2; i * i <= k; i++) { // n 为被分解数
// 以sqrt(n)为界 如果一个数在左边,必然有一个数在右边,不用求完 只需要求一半(i*i)就行 就可以判断是不是质数
if (k % i == 0) {
// 不是质数 开始分解
while (k % i == 0) {
// 相除
k /= i;
st[i]++;
// 对应位置次数+1
}
}
}
if (k > 1) {
st[k]++;
}
}
System.out.println(Arrays.toString(st));
long l = 1;
for (int i = 1; i < st.length; i++) {
if (st[i] != 0) {
l *= (st[i] + 1);
}
}
System.out.println(l);
这样子代码就写出来了
if (k > 1) {
st[k]++;
}
我们可以看到一重循环结束后有一个这个东西,可能有同学会觉得k可能会是合数影响结果,实际上k是2-100都不能除尽剩下的东西,它只能是个质数。所以并不需要担心这个数破坏了唯一分解定理