线性筛

线性筛

引入


-例题(F题)

给定两个正整数\(n\),\(q\)然后询问\(q\)次,每次询问第\(m\)小的质数保证质数小于等于\(n\)。

-思路

用数组把质数进行存储,再输出第\(m\)个便可以了,但是我们需要考虑时间空间限制,一般题暴力也可以,但有些唐题就想要让我们用线性筛。接下来进行讲解,供各位鉴赏。

线性筛


-原理

在遍历到某一个数字\(k\)时,如果\(k\)是质数,那么它的倍数(\(2*k\),\(3*k\)...\(n*k\))必然不是质数,若\(k\)不是质数,它必定被前面的某个质数排掉。

-核心代码

c 复制代码
vector<bool> prime(n+1,true);//用数组存下0-n,默认每个数都是质数(true)
prime[0]=prime[1]=false;//0,1不是质数(fales)
for(int i=2;i*i<=n;++i){//遍历(Q1:为什么是i*i?)
	if(prime[i]){
		for(int j=i*i;j<=n;j+=i){//对这个质数的平方后的倍数排除(Q2:为什么从i*i开始?)
			prime[j]=false;//排除
		}
	} 
}

-Tips

Q1:

合数的性质:

如果 n 是合数,那么它至少有一个质因数 p 满足 p ≤ √n。

例如,n = 100,√100 = 10。如果 n 是合数,它至少有一个质因数 p ≤ 10。

筛法的终止条件:

当 i > √n 时,ii > n,此时 i 的倍数 i 2, i3, ..., i(i-1) 已经被更小的质数筛除了。

因此,继续筛除已经没有意义。

Q2:

合数的性质:

如果 n 是合数,那么它至少有一个质因数 p 满足 p ≤ √n。

例如,n = 100,√100 = 10。如果 n 是合数,它至少有一个质因数 p ≤ 10。

筛法的起始点:

对于质数 i,i 的倍数 i2, i3, ..., i*(i-1) 已经被更小的质数筛除了。

因此,直接从 j = i * i 开始筛除。

上代码


C 复制代码
#include <bits/stdc++.h>
using namespace std;

int main() {
	int n,q,m;
	cin>>n>>q;
	vector<bool> prime(n+1,true);
	prime[0]=prime[1]=false;
	for(int i=2;i*i<=n;++i){
		if(prime[i]){
			for(int j=i*i;j<=n;j+=i){
				prime[j]=false;
			}
		} 
	}
	
	vector<int> primes;//存入质数
    for(int i=2;i<=n;++i){
        if(prime[i]) primes.push_back(i);
    }
	
	while(q--){//多次询问
		cin>>m;
		if(m>=1&&m<=primes.size()){
			cout<<primes[m-1]<<endl;
		}else{
			cout<<-1<<endl;
		}
	}
	
	
    return 0;
} 

题解++,任务--!

感谢观看!