各种筛法

一、质数筛法

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]);
        }
    }
}
posted @ 2022-06-10 23:24  nofind  阅读(99)  评论(0编辑  收藏  举报