唯一分解定理

前言

先讲唯一分解定理是个啥,然后用一个经典例题来巩固一下就O~er了。

一、理论

  • 定义:
    任意一个正整数nn>1),一定存在一个全为质数的集合(这个集合中所有元素 x i ≤ n xi \leq n xin) {P1e1,P2e2,P3e3……,Pkek} (Pi>1,ei>=1,i>=1),这个集合所有元素相乘,结果就等于n

  • 示例1——30的唯一分解:
    因为:30=2x3x5.
    所以30的唯一分解后得到一个质数集合:{2,3,5}.

  • 示例2——84的唯一分解:
    因为:84= 2 2 2^{\color{red}2} 22x3x7
    所以84通过唯一分解得到的质数集合:{2,3,7}.

  • 补充: 以上的质数集合必定是唯一的! 如果你发现了不止一个满足上述条件的集合,您过来打我,我发地址给您。🫡🫡🫡

二、经典例题

1、题目描述

蓝桥云课连接
在这里插入图片描述

2、算法原理&AC代码

什么是质因子?

这个因子质数,那么就是质因子
那么什么是因子 呢?很简单,如果一个整数x,可以整除原来的数nn/x==整数),那么x就是n的因子。

题目要求给定一个数N ,( 1 ≤ N ≤ 1 0 12 1 \leq N \leq 10^{12} 1N1012),求对应的所有质因数。这不就是求一个数,通过唯一分解定理得到的所有质数的集合吗?也就是说,N=30,那么答案就是{2,3,5};N=84 ,那么答案就是{2,3,7}。

所以思路就清晰了,我们直接在区间[2,N]遍历所有的质数,判断这个质数是否是唯一分解定理里面的集合,是就打印,不是就往右边遍历,直到为N。

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int N=scan.nextInt();

        for(int i=2;i<N+1;i++){
        }
    }
}

那么如何i是否属于N的质数集合呢?
接下来的文字都很重要,必须认真看了哈。
请看这个式子:

i1e1 x i2e2 x i3e3 x …… x ikek = N e ≥ 1 e\geq 1 e1

我们需要的答案实际上就是等式左边所有指数的底数: i1、i2、i3、……ik .
这些底数i,有一个共同的特点,就是它们都是整数,所以N除以任意一个i,其结果也是一个整数。
所以判断当前枚举的i是否是答案,直接N%i==0即可,等于零是整数,说明这个i就是质因子。我们这种操作实际上就有点想拿着答案去反推过程:

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        long N=scan.nextLong();
        for(Long i=2;i<N+1;i++){
            //获取可能的质数
            if(N%i==0){
                System.out.println(i+" ");
            }
        }
    }
}

代码这样些就完成了吗?
其实没有,每当我们遍历到一个需要打印的i后,需要更新N的大小:

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        long N=scan.nextLong();

        for(long i=2;i<N+1;i++){

            //获取可能的质数
            if(N%i==0){
                System.out.println(i+" ");
            }
            
            //更新N,保证后续遍历的正确性
            while(N%i==0){
                N/=i;
            }
        }
    }
}

这样做的目的是确保我们之前的式子是一致成立的:
i1e1 x i2e2 x i3e3 x …… x ikek = N
假如 i1 已经遍历到并且打印了,并且e1=2,那么通过while循环式子就会变成:
i2e2 x i3e3 x …… x ikek = N / i1e1
这充分利用了唯一分解定理,来准确获取质因子。

最后如果问题规模不大,那么问题也就解决了,但是测试用例中出现了时间超限:在这里插入图片描述
所以我们需要对上面这个代码做一下优化:
原来代码的时间复杂度实际上我们只需要改造for循环 ,我们可以把循环数量降低一点(最终的AC代码):

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        long N=scan.nextLong();

        //变成平方根
        for(long i=2;i<=Math.sqrt(N);i++){
            if(N%i==0)System.out.print(i+" ");
            while(N%i==0){
                N/=i;
            }
        }
		
		//判断是否会遗漏大于N的平方根的质因子,遗漏补上
          if(N>1)System.out.print(N);
    }
}

可以这样操作的原因是因数永远是成对出现的:(如果您找到不成对出现的因子,您来打我,我把地址发给您。🫡🫡🫡)

  • 36的因数:
    {2,18} {4,9} {6,6}

  • 27的因数:
    {3,9}

  • 9的因数:
    {3,3}

  • ……

还记得刚才的代码吗?

 if(N%i==0)System.out.print(i+" ");
            while(N%i==0){
                N/=i;
            }

我们在从左到右枚举每一个可能的数字,当枚举到一个可能的质数,这个质数一定对应着另一个因子。比如对于36,枚举到二的时候,那么一定对应另一个因子18(因为2x18=36),当我们打印这个因子后,我们会进入while循环,每取一次模,对应的因子就会-1,直到右侧因子每%完。因此我们只需要从2枚举到 36 = 6 \sqrt{36} = 6 36 =6即可。

这些成对的因子有这种特性:要么一个小于 N \sqrt{N} N ,一个大于 N \sqrt{N} N ;要么两个因子都等于 N \sqrt{N} N 但绝不可能一对因子,全部大于 N \sqrt{N} N
所以i,只用枚举到 N \sqrt{N} N 即可,为了避免遗漏掉大于 N \sqrt{N} N 的因子(i没有遍历到),我们再最后增添一个if条件句即可。


这种题目说实话,对与咱们没有数学天分的人来说,我觉得还是很有难度的。因为它几乎考的就是数学思维。因此如果一遍没看懂,不用气馁,回头可以再仔细看一下。欢迎留言提问~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值