1、埃拉托斯特尼筛法
const int MAXN = 1000000; void Prime() { for (int i=0; i<MAXN; i++) prime[i]=1; //先把每个数都定义为合数 prime[0]=prime[1]=0; for (int i=2; i<MAXN; i++) { if (!prime[i]) continue; //如果为0就跳过,说明是素数 for (int j=i*2; j<MAXN; j+=i) prime[j] = 0; //将i的倍数标记为合数 //筛去2的倍数4、6、8,筛去3的倍数... } }
2、欧拉筛
//O(n)的筛法,每个合数只被它的最小质因子筛一次 //每一次的外循环筛出i和找到的质数 int maxn; int prime[120000];//prime[0]记录当前为止找到的素数的个数,1~maxn存找到的素数 int visit[120000];//其值为0时是素数,1~maxn用来打表 void Prime() { memset(visit,0,sizeof(visit)); memset(prime, 0,sizeof(prime)); for (int i = 2; i <= maxn; i++) { // cout<<" i = "<<i<<endl; if (!visit[i]) { prime[++prime[0]] = i;//记录素数的个数,同时存找到的素数 } for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++)//遍历每一个已找到的素数并且素数的倍数小于等于maxn { // cout<<" j = "<<j<<" prime["<<j<<"]"<<" = "<<prime[j]<<" i*prime[j] = "<<i*prime[j]<<endl; visit[i*prime[j]] = 1;//这个素数的倍数是合数 if (i % prime[j] == 0)//因为每个数只被它的最小质因子筛一次,在此之后的质数不用筛,以后会筛 { break; } } } }
3、Miller-Rabin判断法
#include<bits/stdc++.h> #define ll long long using namespace std; ll qpow(ll x,ll y,ll p)//x^y mod p { ll ans=1,m=x; while(y) { if(y&1)ans*=m; ans%=p; m*=m; m%=p; y>>=1; } return ans; } bool check(ll x,ll y,ll p) { ll q=qpow(x,y,p); if(q!=1&&q!=p-1)return 0; if(q==p-1)return 1; if(q==1&&(y&1))return 1; return check(x,y>>1,p); } bool mil(ll x) { if(x<=1)return 0; if(x==2||x==7||x==61||(check(2,x-1,x)&&check(7,x-1,x)&&check(61,x-1,x)))/*底数RP++*/return true; return 0; } int main() { int n,m; ll k; cin>>n>>m; for(int i=1;i<=m;i++) { cin>>k; if(mil(k))cout<<"Yes"<<endl; else cout<<"No"<<endl; } return 0; }
由于暂时看不懂.....先搁在这
可以参考下https://www.cnblogs.com/bytebull/p/11179316.html
luoguP3912 素数个数
题目描述
求 1,2,⋯ ,N1,2,cdots,N1,2,⋯,N 中素数的个数。
输入格式
一行一个整数 NNN。
输出格式
一行一个整数,表示素数的个数。
输入输出样例
输入 #1
10
输出 #1
4
说明/提示
对于 40% 的数据,1≤N≤10^6。
对于 80% 的数据,1≤N≤10^7。
对于 100% 的数据,1≤N≤10^8。
解题思路
类似埃拉托斯特尼筛法,稍微做点改进
#include<bits/stdc++.h> using namespace std; bool a[100000000];//其值为0是素数 int main() { int n,i,j,s=0; cin>>n; memset(a,0,sizeof(a)); s=n-1;//去1 for(i=2; i*i<=n; i++) { if(a[i]==0) for(j=i*2; j<=n; j+=i) if(a[j]==0) {//j必为合数,则去合数 cout<<" i = "<<i<<" j = "<<j<<endl; a[j]=1; s--; } } cout<<s;
return 0; }
P1835 素数密度
题目描述
给定区间[L,R](L≤R≤2147483647,R-L≤1000000)
,请计算区间中素数的个数。
输入格式
两个数L和R。
输出格式
一行,区间中素数的个数。
输入输出样例
输入 #1
2 11
输出 #1
5
解题思路
看数据范围用简单筛法明显不行,不过呢L~R的范围很小
只要筛掉√2147483647内所有质数,然后用这其中的质数筛[l,r]内的数#include<bits/stdc++.h> using namespace std; #define int long long const int maxn = 1000000; int l , r; int prime[maxn] , cnt=0 , tot=0;//cnt为质因子个数,tot为答案 bool vis[maxn]; bool ans[maxn]; void Euler() { for(int i = 2 ; i <= 50000 ; ++ i) { if(!vis[i]) { prime[++cnt] = i; for(int j = i + i ; j <= 50000 ; j += i) { vis[j] = 1; } } } } int _max(int a , int b) { return a > b ? a : b; } signed main () {//因为前面 #define int long long了,这里int = signed int = signed Euler(); cin>>l>>r; for(int i = 1 ; i <= cnt ; i++) { for(int j = _max( 2 , (l - 1)/prime[i] + 1) * prime[i] ; j <= r ; j += prime[i]) if(j - l >= 0) ans[j - l]=1;//等于1为合数 } for(int i = 0 ; i <= r - l ; i++) if(!ans[i]) tot ++; cout<<tot; return 0; }
P3383 【模板】线性筛素数
题目背景
本题已更新,从判断素数改为了查询第 kkk 小的素数
提示:如果你使用 cin
来读入,建议使用 std::ios::sync_with_stdio(0)
来加速。
题目描述
如题,给定一个范围 n,有 q 个询问,每次输出第 k 小的素数。
输入格式
第一行包含两个正整数 n,q分别表示查询的范围和查询的个数。
接下来 q行每行一个正整数 k,表示查询第 k小的素数。
输出格式
输出 q 行,每行一个正整数表示答案。
输入输出样例
输入 #1
100 5 1 2 3 4 5
输出 #1
2 3 5 7 11
说明/提示
【数据范围】
对于 100% 的数据,n=108n = 10^8n=108,1≤q≤10^6,保证查询的素数不大于 n。
Data by NaCly_Fish.
解题思路
用欧拉筛可以,但要注意数组的大小
#include<bits/stdc++.h> using namespace std; int prime[6000010]; bool visit[100000010];//1为素数 void getPrime(int maxn) { memset(visit,1,sizeof(visit)); memset(prime,0,sizeof(prime)); visit[1]=0; for (int i = 2; i <= maxn; i++) { if (visit[i]) { prime[++prime[0]] = i; } for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) { visit[i*prime[j]] = 0; if (i % prime[j] == 0) { break; } } } } int main(){ int n,k,maxn; cin>>maxn>>n; getPrime(maxn); for(int i=1; i<=n; i++){ cin>>k; cout<<prime[k]<<endl; } return 0; }