各种筛法
一、质数筛法
1.Eratosthenes筛法:
从\(2\)开始,由大到小扫描每个数\(x\),将其的倍数\(2x,3x,...[N/x]*x\)标记为合数。当扫描到一个数时,若它未被标记,则它不能被\([2,x-1]\)之间的任何数整除,该数为质数。
复杂度\(O(NloglogN)\)。
点击查看代码
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* @author dongyudeng
*/
public class Eratosthenes {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt(), q = scanner.nextInt();
boolean[] visited = new boolean[n + 1];
List<Integer> list = new ArrayList<>();
for (int i = 2; i <= n; i++) {
if (visited[i]) continue;
list.add(i);
for (int j = i; j <= n / i; j++) visited[i * j] = true;
}
while ((q--) > 0) {
int k = scanner.nextInt();
System.out.println(list.get(k - 1));
}
}
}
2.线性筛法:
考虑在上述筛法中重复标记的情况,比如\(12\),它既会被\(2\)标记又会被\(3\)标记,我们要使得标记\(12\)的方式唯一。
我们令\(min_i\)表示\(i\)的最小质因子,并通过以下方法维护\(min\):
1.依次考虑\([2,N]\)之间的每一个数\(i\)。
2.若\(min_i=i\),说明\(i\)为质数,将其保留。
3.扫描不大于\(min_i\)的每个质数\(p\),令\(min_{i*p}=p\)。
由于每个合数\(i*p\)只会被\(p\)筛一次,时间复杂度为\(O(N)\)。
点击查看代码
import java.util.Scanner;
/**
* @author dongyudeng
*/
public class LinearSieve {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt(), q = scanner.nextInt(), m = 0;
int[] min = new int[n + 1], primes = new int[n + 1];
for (int i = 2; i <= n; i++) {
if (min[i] == 0) {
min[i] = i;
primes[++m] = i;
}
for (int prime : primes) {
if (prime > min[i] || prime > n / i) break;
min[i * prime] = prime;
}
}
while ((q--) > 0) {
int k = scanner.nextInt();
System.out.println(primes[k]);
}
}
}