素数筛的总结与记录

目录:(1,2判断一个属是否为素数数据范围较小,3,4可用于大数据,4,5可用于求区间素数个数)

  1. 素数定义法
  2. 六倍判定法
  3. 埃氏筛
  4. 欧拉筛
  5. 区间筛
  6. 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算法

全部评论

相关推荐

01-14 16:23
广州商学院 Java
双非后端失败第N人:如果准备好了可以直接投字节,字节是最不看学历的,只要想面,大概率都能给你约面。
双非有机会进大厂吗
点赞 评论 收藏
分享
01-28 16:12
中南大学 Java
几年前还没有chatgpt的时候,刷题真的是很痛苦。刷不出来只能看题解,题解有几个问题:第一个是每次看的写题解的人都不一样,很难有一个统一的思路;第二个也是最重要的是,题解只提供了作者自己的思路,但是没有办法告诉你你的思路哪里错了。其实很少有错误的思路,我只是需要被引导到正确的思路上面去。所以传统题解学习起来非常困难,每次做不出来难受,找题解更难受。但是现在chatgpt能做很多!它可以这样帮助你&nbsp;-1.&nbsp;可以直接按照你喜欢的语言生成各种解法的题解和分析复杂度。2.&nbsp;把题和你写的代码都发给它,它可以告诉你&nbsp;你的思路到底哪里有问题。有时候我发现我和题解非常接近,只是有一点点🤏想错了。只要改这一点点就是最优解。信心倍增。3.&nbsp;如果遇到不懂的题解可以一行一行询问为什么要这样写,chatgpt不会嫌你烦。有时候我觉得自己的range写错了,其实那样写也没错,只是chat老师的题解有一点优化,这个它都会讲清楚。4.&nbsp;它可以帮你找可以用同类型解法来做的题。然后它可以保持解法思路不变,用一个思路爽刷一个类型的题。如果题目之间思路又有变化,它会告诉你只有哪里变了,其他的地方还是老思路。5.&nbsp;它也可以直接帮你总结模板,易错点。经过chat老师的指导,我最大的改变是敢刷题了。之前刷题需要先找某一个人写的算法题repo,然后跟着某一个人他的思路刷他给的几个题。如果想写别的题,套用思路失败了,没有他的题解,也不知道到底哪里错了;看别人的题解,思路又乱了。这个问题在二分查找和dp类型的题里面特别常见。但是现在有chat老师,他会针对我的代码告诉我我哪里想错了,应该怎么做;还按照我写代码的习惯帮我总结了一套属于我的刷题模板。每天写题全是正反馈!
牛客981:不刷才是爽
AI时代的工作 VS 传...
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务