杭电ACM OJ 1019 Least Common Multiple 质因子最快速求最大公因数和最小公倍数

本文介绍了如何利用质因子分解的方法,高效地解决杭电ACM在线评测(OJ)中1019题目的最小公倍数(LCM)问题。通过对数的质因子分解,可以快速找到两个数的最大公因数(GCD)并计算它们的最小公倍数。这种方法对于理解质因子在数论问题中的应用具有重要意义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Least Common Multiple

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 56268    Accepted Submission(s): 21413


Problem Description
The least common multiple (LCM) of a set of positive integers is the smallest positive integer which is divisible by all the numbers in the set. For example, the LCM of 5, 7 and 15 is 105.

 

Input
Input will consist of multiple problem instances. The first line of the input will contain a single integer indicating the number of problem instances. Each instance will consist of a single line of the form m n1 n2 n3 ... nm where m is the number of integers in the set and n1 ... nm are the integers. All integers will be positive and lie within the range of a 32-bit integer.
 

Output
For each problem instance, output a single line containing the corresponding LCM. All results will lie in the range of a 32-bit integer.
 

Sample Input
2 3 5 7 15 6 4 10296 936 1287 792 1
 

Sample Output
105

10296

翻译:求多个数的最小公倍数

核心:明白求质因子的最快方法,可以参看我的博客快速求质因子,这里我也简单讲一下

虽然是java代码,但是和c c++也差不多

private static List<Integer> getPrimeFactor(int num) {
    List<Integer> primeFactorList = new ArrayList<>();
    for (int i = 2; i * i < num; i++) {
        if (num % i == 0) {
            primeFactorList.add(i);
            while (num % i == 0) num = num / i;
        }
    }
    if (num > 1) primeFactorList.add(num);
    return primeFactorList;
}

就是和正常求质因子不同的是,这里添加了这样一个操作

while (num % i == 0) num = num / i;
这就是为了求出一个因子以后,这一类的因子以后都不用再考虑了,大大缩小了num的长度,增加了效率。


此外

if (num > 1) primeFactorList.add(num);
由于num大大缩小,不会像原来一样遍历完全,所以可能会漏掉num本身。



所以问题就简单了。


此外还需要考虑一个问题,两个数之间的乘积 = 两个数的最大公因数 * 两个数的最小公倍数;

(原因:假设m = a*c,n = b *c(ab互质),那么他们的公因数就是c,公倍数就是abc,乘积就是abcc,相等)

但是这个原理对多个数不适用,你们可以也一样地推一下。

所以我们应该求出互不相同质因子的乘积,再去用乘积的2倍,3倍。。一直遍历到可以把所有数的乘积整除,这样就行了,非常简单。


我把每个功能都分成了一个个小模块 十分的清晰

public class LeastCommonMultiple1019 {
    List<Integer> list = new ArrayList<>();

    //初始化list
    LeastCommonMultiple1019(Integer...i) {
        Collections.addAll(list, i);
    }

    //list里的每个整数都求出质因子来,放入一个新集合,再把所有的集合放入一个新的乘方集合的集合,
    //相当于二维数组
    private List<List<Integer>> getPrimeFactor(List<Integer> list) {

        List<List<Integer>> allList = new ArrayList<>();

        for (int i : list) {

            List<Integer> mList = new ArrayList<>();

            int num = i;
            for (int j = 2; j * j < num; j ++) {

                if (num % j == 0) {
                    mList.add(j);

                    while (num % j == 0) num /= j;//一次性彻底消除一种因子

                }

            }
            if (num > 1) mList.add(num);

            allList.add(mList);

        }

        return allList;
    }

    //根据这个二维数组,找出每一列存放的质因子,留下互不相同的质因子
    private List<Integer> getPrimeList(List<List<Integer>> list) {

        List<Integer> primeList = new ArrayList<>();

        for (List<Integer> mList : list) {
            for (int i : mList) {
                if (!primeList.contains(i)) {
                    primeList.add(i);
                }
            }
        }

        return primeList;

    }

    //把互不相同的质因子,进行处理,返回结果
    private int getResult(List<Integer> list) {

        int product = 1;
        for (int i : list) {
            product *= i;
        }

        int max = -1;
        for (int i : this.list) {
            if (max < i) {
                max = i;
            }
        }

        int i = 2;
        while ((product * i) % max != 0) {
            i ++;
        }

        return product * i;

    }

    private int getAnswer() {
        List<List<Integer>> list = getPrimeFactor(this.list);
        List<Integer> primeList = getPrimeList(list);
        return getResult(primeList);
    }

    public static void main(String[] args) throws Exception {

        LeastCommonMultiple1019 leastCommonMultiple1019 = new LeastCommonMultiple1019(6,4,10296,936,1287,792,1);
        int answer = leastCommonMultiple1019.getAnswer();
        System.out.println(answer + "");

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值