线性筛
引入
-例题(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;
}
题解++,任务--!
感谢观看!