素数(素数判定 , 素数筛 , 唯一分解定理 , 约数定理)

  • 素数的定义
    指在大于1的自然数中,除了1和它自身之外,不能被任何其他自然数整除的数 叫做质数;否则称为合数
    (0和1,既不是素数,也不是合数)

素数判定

//暴力法

boolean isPrime(int n){
    for(int i=2;i<n;i++){
        if(n%i==0){
            return false;        
        }    
    }
    return true;
}

//试除法(暴力法的优化)
//i遍历到n.sqrt()即可判断n是否为素数
/*
可以通过反证法证明:
假设遍历到n.sqrt()仍然无法判断n是否为素数,
则存在自然数a,b;使得n=a*b
同时a,b中必有一数大于n.sqrt();那么另一数一定小于n.sqrt()
较小的数一定会在n.sqrt()前被遍历到。
与假设矛盾
*/
/*
为什么写为i<=n/i    ——->假设i是n的因子,那么n/i也是n的因子
故而可以枚举到i<=n/i
*/
boolean isPrime(int n){
    for(int i=2;i<=n/i;i++){
        if(n%i==0){
            return false;        
        }    
    }
    return true;
}

素数筛(埃氏筛)

理解:素数的倍数一定是合数
基本思路:给定范围n,从2开始,将每个素数的倍数标记为合数。那么一个数没有被之前的数标记,它一定是素数

public class PrimeSieve {
    public static void main(String[] args) {
        int n = 100; // 要筛选的范围
        boolean[] isPrime = new boolean[n + 1];
        Arrays.fill(isPrime, true);
        isPrime[0] = isPrime[1] = false;

        for (int i = 2; i * i <= n; i++) {
            if (isPrime[i]) {
                for (int j = i * i; j <= n; j += i) {
                    isPrime[j] = false;
                }
            }
        }

        System.out.println("小于等于" + n + "的素数有:");
        for (int i = 2; i <= n; i++) {
            if (isPrime[i]) {
                System.out.print(i + " ");
            }
        }
    }
}

唯一分解定理

任何一个大于1的整数n都可以分解成若干个素因数的连乘积,如果不计各个素因数的顺序,那么这种分解是唯一的

  • 唯一分解定理公式:(某个质因子(p)的个数)
    在这里插入图片描述

  • 举个例子更容易理解:

      eg.求n!中 5的个数--》也就是求n!中末尾为0的个数
    

代码如下:

public static int check(int n) {
        int count = 0;
        while (n > 0) {
            n /= 5;
            count += n;
        }
        return count;
    }

不是求n!中5的个数吗?为什么传参只传了n?
因为在计算n!时,是求123*…*n。也就是统计1到n中所有数的因子5的个数之和
在计算n!中因子5的个数时,一些数会贡献因子5
而n中包含了这些数贡献的因子5
所以计算n!中5的个数的总和,其实就是n中包含5的个数

例如:
15/5 = 3	//15!中就包含了3个5
25/5 = 5 ; 5/5 =1  sum=5+1--->//25!中就有6个5

蓝桥真题:求阶乘

问题描述:满足N!的末尾恰好有K个0的最小N是多少?如果不存在这样的N 输出-1
在这里插入图片描述

//还是有超时的可能
import java.util.*;
public class Main{
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		long k = scan.nextLong();
		//有k个0,就是有k个5
		long l = 1L;
		long r = Long.MAX_VALUE;
		//二分法
		while(l<r) {
			long mid = (l+r)/2;
			if(check(mid) >= k) r = mid;
			else if(check(mid)<k) l = mid+1;
		}
		if(check(r) == k) {
			
			System.out.println(r);
		}else {
			System.out.println(-1);
		}
	}
	
	public static long check(long mid) {
		long count = 0;
		//计算n中有多少个5--->唯一分解定理的质因子个数公式---》n!中有多少个5
		while(mid!=0) {
			count+=mid/5;
			mid = mid/5;
		}
		return count;
	}
}
eg. 100=2*2*5*5
c++
/**
 * 功能:分解质数因数
 * @param x 待分解的数字
 * @param a 分解后的数组
 * @return 数组的最后一个元素下标
 */
int Decomposition(int x, int a[]) {
    int cnt = 0;
    for (int i = 2; i <= x / i; i++)
        while (x % i == 0) {
            x /= i;
            a[++cnt] = i;
        }
    if (x > 1)a[++cnt] = x;
    return cnt;
}

const int N = 110;
int a[N];

//用法:
int cnt = Decomposition(12, a);
for (int i = 1; i <= cnt; i++) cout << a[i] << " ";

约数定理

n可以分解质因数:n=p1a1*p2a2*…*pk^ak (pk是素数 ak是pk的指数)
则,p1^a1 的约数有:p10,p11,….,p1^a1,共(a1+1)个
同理,p2^a2 的约数有(a2+1)个….pk^ak约数个数有(ak+1)个

参考资料

  • 【约数定理(约数个数定理,约束和定理) - 优快云 App】https://blog.youkuaiyun.com/piaocoder/article/details/47954385?utm_source=app&app_version=6.3.0
  • 【大整数分解——Pollard Rho算法 - 优快云 App】http://t.csdnimg.cn/ID2BFv
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值