浅谈筛法
假期一到,随着竞赛集训结束,也是终于放假了!但是假期只有一半,但是还有竞赛作业...其中一项便是写4篇题解,本人也借此机会温习一下旧知识(绝对不是想水题解),第一篇就分享一下筛法,欢迎交流讨论!
引入
-例题
给定两个正整数\(n\),\(q\)然后询问\(q\)次,每次询问第\(m\)小的质数保证质数小于等于\(n\)。
-思路
用数组把质数进行存储,再输出第\(m\)个便可以了,但是我们需要考虑时间空间限制,一般题暴力也可以,但有些唐题就想要让我们用线性筛。接下来进行讲解,供各位鉴赏。
埃氏筛
-原理
在遍历到某一个数字\(k\)时,如果\(k\)是质数,那么它的倍数(\(2*k\),\(3*k\)...\(n*k\))必然不是质数,若\(k\)不是质数,它必定被前面的某个质数排掉。
-核心代码
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。
Q2:
筛法的起始点:
对于质数 i,i 的倍数 \(i*2\), \(i*3\), ...,$ i*(i-1) $已经被更小的质数筛除了。
因此,直接从 j = i * i 开始筛除。
上代码
#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;
}
题解++,任务--!
感谢观看!
本文作者:ccgc718
本文链接:https://www.cnblogs.com/ccgc718/p/18696762
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步