素数筛的总结与记录
目录:(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算法
OPPO成长空间 955人发布
查看19道真题和解析