素数筛的总结与记录
目录:(1,2判断一个属是否为素数数据范围较小,3,4可用于大数据,4,5可用于求区间素数个数)
- 素数定义法
- 六倍判定法
- 埃氏筛
- 欧拉筛
- 区间筛
- Miller-Rabin算法
第一款:素数定义判断法
复杂度n^(1/2)
int prime1(long long x)//暴力法 { long long i; int flag=1; if(flag==1)return 0;//特判1不是素数 for(int i=2;i<=sqrt(x);i++)//遍历1到x^1/2的每个数 找到可能的因子 { if(x%i==0) { flag=0; break; } } return flag; }
第二款:六倍法判断素数
int prime2(int n)//六倍判断法 { if (n==2||n==3){ return 1; } if (n%6!=1&&n%6!=5){ return 0; } for (int i=5;i<=sqrt(n);i+=6){ if (n%i==0||n%(i+2)==0){ return 0; } } return 1; }
第三款:埃氏筛
//求区间里的所有素数 const int maxn = 1e4; bool number[maxn+10]; void prime3() { int i, j; memset(number, true, sizeof(number));//将所有数标记为素数 number[0]=false;number[1]=false; for (i = 2; i <= maxn; i++) { if (number[i] == true) { for (j = i*i; j <= maxn; j+=i) number[j] = false;//将合数筛选出来 } } }
第四款:欧拉筛
#include<bits/stdc++.h> using namespace std; const int maxn=1e5;//数组的大小 const int N=1e5;//最大的质数的大小 bool vis[maxn]; int prime[maxn],cnt; void init() { memset(vis,false, sizeof(vis));//所有数初始化为0->质数 vis[0]=true; vis[1]=true; cnt=0; } void Is_Prime() { init(); for(int i=2;i<=N;i++) { if(!vis[i])//i是质数 prime[++cnt]=i;//prime是用来存质数的数组,显然数组中的质数是从小到大 for(int j=1;j<=cnt;j++) { if(i*prime[j]>N)//超出了范围 break; vis[i*prime[j]]=true; if(i % prime[j] == 0)//跑到了i的最小的质因数 break; } } }
第五款:区间筛
//区间筛 用于求区间a,b中间素数的个数 bool v1[Max_n1]; //数组大小为sqrt(b) bool v2[Max_n2]; //数组大小为b-a #define long long ll ll Prime(ll a,ll b){ for(ll i=0;i*i<b;i++)v1[i]=true; for(ll i=0;i<b-a;i++)v2[i]=true; for(ll i=2;i*i<b;i++){ if(v1[i]){ for(ll j=2*i;j*j<b;j+=i)v1[j]=false; //筛[2,b) for(ll j=max(2LL,(a+i-1)/i)*i;j<b;j+=i)v2[j-a]=false; //筛[a,b) //2LL是2的长整数形式 //((a+i-1)/i)*i是符合>=a最小是i倍数的数 } } ll k=0; for(ll i=0;i<b-a;i++){ if(v2[i])k++; } return k; }
6.Miller-Rabin算法快速判断大数是否为素数
(数学解释没理解 只会用板子)
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll qul_mul(ll a, ll b, ll n) //快速积运算,快速求出a^m^*a^m^并且能防止爆掉 { ll num = 0; while (b) { if (b&1) { num=(num+a)%n; } a = (a+a)%n; b>>=1; } return num; } ll qul_pow(ll a, ll b, ll n) //快速幂计算快速求出a^m^的值 { ll sum = 1; while (b) { if (b&1) { sum = sum * a % n; } a=a*a%n; b>>=1; } return sum; } bool Miller_Rabin(ll n) { int m = n-1; int t = 0; if (n==2) { return true; } else if (n<2 || !(n&1)) { return false; } //求出n-1 = m*2^t的m和t。 while (!(m&1)) { m>>=1; t++; } for (int i=0; i<20; i++) { //随机数a ll a = rand()%(n-1) + 1; // 计算a^m ll x = qul_pow(a, m, n), y; for (int j=0; j<t; j++) { y = qul_mul(x, x, n); //进行(x*x)%n操作。 //不满足二次探测定理,也就是y得1了但是x并不等于1或者n-1,那么n就一定不是质数。 if (y==1 && x!=1 && x!=n-1) { return false; } x = y; } //上面循环跑完了,如果最后x都不等于1,那么一定是一个合数了。 if (x!=1) { return false; } } return true; } int main() { ll n; while (cin >> n) { if( Miller_Rabin(n)==true) cout <<"yes"<<endl; else cout<<"no"<<endl; } return 0; }
参考文章:
1.素数筛详解
2.素数_埃氏筛法&&线性筛(欧拉筛法)【详解】
埃氏筛法、区间筛法(求素数个数)
Miller-Rabin算法