Acwing---1295. X的因子链

文章介绍了如何使用线性筛法(欧拉筛法)在O(N)的时间复杂度内找出所有质数,并利用这种方法解决寻找正整数X的因子链问题。因子链是要求每个因子都能整除其后一个因子,文章提供了代码实现来找出最大长度的因子链及其个数。
摘要由CSDN通过智能技术生成

1.题目

输入正整数 X,求 X的大于 1 的因子组成的满足任意前一项都能整除后一项的严格递增序列的最大长度,以及满足最大长度的序列的个数

输入格式
输入包含多组数据,每组数据占一行,包含一个正整数表示 X。

输出格式
对于每组数据,输出序列的最大长度以及满足最大长度的序列的个数。

每个结果占一行。

数据范围
1 ≤ X ≤ 1≤X≤ 1X 2^20

输入样例:

2
3
4
10
100

输出样例:

1 1
1 1
2 1
2 2
4 6

2.基本思想

算术基本定理

就是因式分解的定理,所有的整数都可以唯一分解成若干个质因子乘积的形式
在这里插入图片描述

筛法求素数——线性筛法(欧拉筛法)
参考文章

在O(N)的时间复杂度内,求出来1 ~ n中所有的质数,以及每一个数的最小质因子。

① 筛掉的一定是合数,且一定是用其最小质因子筛的

② 合数一定会被筛掉
在这里插入图片描述
这样我们就可以把所有质数找出来,而且每个和数只会被最小质因子筛,所以每个和数只会被筛一次,所以整个算法的时间复杂度为O(N)

在这里插入图片描述

3.代码实现

筛法求素数——线性筛法(欧拉筛法)

import java.util.Scanner;

public class Main {

    static final int N = 1000010;
    static int[] primes = new int[N]; // 存所有的质数
    static int cnt; // 存质数的个数
    static boolean[] st = new boolean[N]; // 当前数有没有被筛过 0没有被筛过 1表示筛过

    public static void main(String[] args) {
        get_primes(100000);

        for (int i = 0; i < 20; i++) System.out.println(primes[i]); // 输出100000的前20个质数
    }

    private static void get_primes(int n) {
        for (int i = 2; i <= n; i++) {
            if (!st[i]) primes[cnt++] = i;
            for (int j = 0; primes[j] * i <= n; j++) {
                /*
                  因为prime中素数是递增的,所以如果i%prime[j]!=0代表i的最小质因数还没有找到,
                  即i的最小质因数大于prime[j]
                  也就是说prime[j]就是i*prime[j]的最小质因数,于是i*prime[j]被它的最小质因数筛掉了
                */
                st[primes[j] * i] = true; // 把质数的i倍筛掉
                /*
                  如果当i%prime[j]==0时,代表i的最小质因数是prime[j],
                  那么i*prime[j+k](k>0)这个合数的最小质因数就不是prime[j+k]而是prime[j]了
                  所以i*prime[j+k]应该被prime[j]筛掉,而不是后续的prime[j+k],于是在此时break
                */
                if (i % primes[j] == 0) break; // 通过最小质因子来筛
            }
        }
    }
}

X的因子链

import java.util.Scanner ;

public class Main {

    static final int N = (1 << 20) + 10;
    static int[] primes = new int[N]; // 存所有的质数
    static int cnt; // 存质数的个数
    static int[] minp = new int[N]; // 存最小质因子
    static boolean[] st = new boolean[N]; // 当前数有没有被筛过

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        get_primes(N - 1);

        int[] fact = new int[30]; // 记录因子
        int[] sum = new int[N]; // 存因子个数

        while (sc.hasNext()) {
            int x = sc.nextInt();
            int k = 0, total = 0;
            while (x > 1) {
                int p = minp[x];
                fact[k] = p;
                sum[k] = 0;
                while (x % p == 0) { // 分解质因数
                    x /= p;
                    sum[k]++;
                    total++;
                }
                k++;
            }

            long res = 1;
            for (int i = 1; i <= total; i++) res *= i; // 求total的阶乘
            for (int i = 0; i < k; i++) { // 多重集合的排列数
                for (int j = 1; j <= sum[i]; j++) {
                    res /= j;
                }
            }

            System.out.println(total + " " + res);
        }
    }

    private static void get_primes(int n) {
        for (int i = 2; i <= n; i++) {
            if (!st[i]) {
                minp[i] = i; // 因为i是质数 最小质因子就是它本身
                primes[cnt++] = i;
            }
            for (int j = 0; primes[j] * i <= n; j++) {
                int t = primes[j] * i;
                st[t] = true;
                minp[t] = primes[j];
                st[primes[j] * i] = true;
                if (i % primes[j] == 0) break;
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

amant 柒少

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值