素数 判断 筛法

判断素数

素数:只有 1 和它本身是因数 。

首先,0 和 1 不是素数,然后 i 从 2 开始判断 i 是不是 n 的因数,如果是因数,则直接返回 n 不是素数,否则,判断 i+1 是不是 n 的因数,直到 的时候,如果 i 仍然不是 n 的因数,那么 n 就是素数。

注:如果一个数 a 能够整除 i ,那么 i 和 a/i 一定满足:假设 i<=a/i , 那么 i<=√n && a/i>= √n 。

public static boolean isprime(int n){
    if(n==0 || n==1)
        return false;
    for(int i=2;i<=n/i;i++){
        if(n%i==0)
            return false;
    }
    return true;
}
求 1 ~ n 中的所有素数----埃氏筛法

思路:如果一个数不是素数,那么这个数一定是 n 个素数的乘积(0 和 1 除外),同理,素数的 k 倍数一定是合数(k>=2) 。

public static void isprime(int n){
    boolean[] isprime = new boolean[n+1];//false表示素数,true表示合数
    for(int i=2;i*i<=n;i++) 
        if(!isprime[i]) //i是质数
            for(int j=2;j*i<=n;j++)//将i的倍数全部标记为合数
                isprime[i*j] = true;
    for(int i=2;i<=n;i++)
        if(!isprime[i])
            System.out.println(i);
}
求1~n中的所有素数----欧拉筛法

思路:每个合数,只被他最小的质因子筛一次。

注:与埃氏筛法不同,埃氏筛法是将素数的倍数,标记为合数;欧拉筛法是将目前已经找到的每一个素数的 i 倍标记为合数,无论 i 是否是素数,同时,如果 i 本身就是素数的倍数,那么就去执行下一个 i 。

public static void isprime(int n){
    boolean[] isprime = new boolean[n+1];
    int[] prime = new int[n];//存储素数
    int count = 0;//统计目前素数个数
    for(int i=2;i<=n;i++) {
        if(!isprime[i])  //i是质数
            prime[count++] = i;//把当前素数存储到数组中count位置
        for(int j=0;j<count && i*prime[j]<=n;j++){//将i的倍数全部标记为合数
            isprime[i*prime[j]] = true;
            if(i%prime[j]==0) break;//欧拉筛法精髓
        }
    }
    for(int i=0;i<count;i++)
        System.out.println(prime[i]);
}
例题:最小质因子之和

题目链接:最小质因子之和(Easy Version) - 蓝桥云课 (lanqiao.cn)

思路:因为题目输入为 T 组数据,如果单独计算每组数据,则会有部分区间的数据被重复计算,所以先通过埃氏筛法,求出每一个数的最小质因子,将结果存放在 ans 数组中,然后将 ans 数组表示为前缀和数组,此时 ans 数组中的结果就为2 ~ n 的质因子之和,此时,题目若输入 15 ,则直接输出 ans[15] 即可。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class 最小质因子之和 {
	static boolean[] isprime  = new boolean[3000001];//是否是素数
	static long[] ans = new long[3000001];//存储最小质因子 i的最小质因子为ans[i],例:ans[4] = 2
	static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
	public static void main(String[] args) throws IOException{
		get(3000000);//题目数据范围,N最大值为3*10^6,将2~3*10^6中每一个数的最小质因子全部求出
		for(int i=2;i<=3000000;i++) {
			ans[i] = ans[i] + ans[i-1];//求前缀和,此时ans[i]中存放的数就是2~i中每一个数的最小质因子的和
		}
		int n = Integer.parseInt(in.readLine());
		while(n-->0) {
			out.println(ans[Integer.parseInt(in.readLine())]);
		}
		out.flush();
	}
	//找出每个数的质因子
	static void get(int n) {
		for(int i=2;i<=n;i++) {
			if(isprime[i])//i不是质数直接跳过,不考虑,i不能作为筛除条件
				continue;
			ans[i] = i;//i为素数,素数的最小质因子就是其本身
			for(int j=2;j<=n/i;j++) {//j为倍数,将素数i的j倍数标记为合数,并将此数的最小质因子标记为i
				if(!isprime[j*i]) {//判断是否已经被标记过
					isprime[j*i] = true;//将i*j标记为合数
					ans[j*i] = i;//j*i的最小质因子是i
				}
			}
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值