判断素数
素数:只有 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
}
}
}
}
}