zoukankan      html  css  js  c++  java
  • 欧拉筛法模板and 洛谷 P3383 【模板】线性筛素数(包括清北的一些方法)

    题目描述

    如题,给定一个范围N,你需要处理M个某数字是否为质数的询问(每个数字均在范围1-N内)

    输入格式

    第一行包含两个正整数N、M,分别表示查询的范围和查询的个数。

    接下来M行每行包含一个不小于1且不大于N的整数,即询问该数是否为质数。

    输出格式

    输出包含M行,每行为Yes或No,即依次为每一个询问的结果。

    当然这是一道很裸的板子题,但是却牵扯到了一个非常有用的东西:

    素数筛法

    首先,我们知道素数筛法主要就是以下几种

    第一:
    无脑筛

    其实就是从2到n遍历一遍,没什么可讲的,顶多把n优化成sqrt(N),所是这种算法的时间复杂度就是O(sqrt(N))不可否定的是,这是已知判断单一数的最快而且是最精准的方法了,绝对不会出错

    第二:

    Miller-rabin素性测试

    如果n为素数,取a<n,设n-1=d*2r,则要么ad≡1(mod n)要么存在0<=i<r,使得ad*2^t≡-1(mod n),要么存在0<=i<r,使得ad*2^t≡-1(mod n)(有可能都满足)

    对于任意一个a,如果满足这两个条件,n有可能是质数,但a如果不满足这两个条件中的任何一个,它一定不是质数。找k个a,如果都满足这两个条件,k-1个“更”有可能是质数

     

    在选取k的时候,最好选取2,3,5,7,13,29,37,89至少保证int范围内不会出错

    因为筛法的不确定性来自于随机的a,但是当选取的数足够好,就没有问题;

     如果n是素数,取a<n,舍n-1=d*2r,则要么ad≡1(mod n),要么存在0<=i<r,使得a

    部分代码:

    int gg[8]={2,3,5,7,13,29,37,89};
    
    long long kuaisumi(long long a,long long b1,long long c)
    {
        long long i=a;
        while(b1)
        {
            if(b1&1) 
            {
                s=(s*i)%c;
            }
            i=(i*i)%c;
            b1>>=1;
        }
        return s%c;
    }
    
    bool miller_rabin(int a,int n)
    {
        int d=n-1,r=0;
        while(d%2==0)
            d/=2,r++;
        int x=kuaisumi(a,d,n);
        if(x==1)return true;
        for(int i=0;i<r;i++)
        {
            if(x==n-1)return true ;
            x=(long long )x*x%n;
        }
        return false;//可以对照素性测试看 
    }
    
    bool is_prime (int n)
    {
        if(n<=1)return false ;
        for(int a=0;a<8;a++)
            if(n==gg[a])return true;//一个个试 
        for(int a=0;a<8;a++)
            if(!miller_rabin(gg[a],n))return false;
        return true;
    }

    现在我们讲一下筛某一个范围的数的方法,

    第三:

    埃拉托色尼筛法(埃氏筛)

    主要思想就是把所有质数的整倍数筛掉,速度比较快,也不难想,时间复杂度o(nloglogn)

    代码实现:

    #include<stdio.h>  
    #include<math.h>
    int main()  
    {  int i,j,k;  
        int a[101];  
        for(i=1;i<=100;i++)   a[i]=i;    
        a[1]=0;               //先挖掉a[1]  
      
        for(i=2;i<sqrt(100);i++){  
            for(j=i+1;j<=100;j++){  
                if(a[i]!=0&&a[j]!=0){  
                    if(a[j]%a[i]==0){  
                        a[j]=0;           //把非素数挖掉,不是素数的都赋值为0  
                    }  
                }  
            }  
        }  
        printf("
    "); 
        for(i=1,k=0;i<=100;i++){  
            if(a[i]!=0){              //选出值不为0的数  即素数   
                //cout<<" "<<a[i];  
                printf("%d ",a[i]);
                k++;  
            }  
      
            if(k==10){      
                printf("
    "); 
                k=0;  
            }  
        }  
        printf("
    "); 
      
        return 0;  
    }

    还有一个是对埃氏筛的优化,叫做欧拉筛,也叫作线性筛

    代码实现:

    #include<cstdio>
    #include<iostream>
    using namespace std;
    int tot,n,b[9999999],pri[9999999];//b[i]存的是i是否为质数,0为质数,1为合数;pri[i]存的是第i个质数
    inline void shai()
    {
      //b[1]=1; 
        for(int i=2;i<=n;i++)//从2到n,因为1不是质数可以跳过,当然有的时候可能会用到b[1],这个时候需要赋特值如上
        {
            if(!b[i])pri[++tot]=i;
            for(int j=1;j<=tot&&i*pri[j]<=n;++j)
            {
                b[i*pri[j]]=1;
                if(i%pri[j]==0)break;//如果i%pri[j]==0,就说明是i的倍数的数一定是某质数的倍数,这个时候就可以把它去掉从而节省时间
            }
        }
    }
    int main()
    {
        cin>>n;
        shai();
        for(int i=1;i<=tot;i++)
        {
            cout<<pri[i]<<endl;//这里是输出n以内的质数,如果想判断一个数是否为质数可以看b[i]
        }
    }

    所有的筛法就讲完了,最后我们贴一下AC代码:

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    using namespace std;
    int tot,n,m,b[9999999],pri[9999999],a[9999999];
    inline void shai()
    {
        for(int i=2;i<=n;i++)
        {
            if(!b[i])pri[++tot]=i;
            for(int j=1;j<=tot&&i*pri[j]<=n;++j)
            {
                b[i*pri[j]]=1;
                if(i%pri[j]==0)break;
            }
        }
    }
    int main()
    {
        cin>>n>>m;
        shai();
        for(int i=1;i<=m;i++)
        {
            cin>>a[i];
        }
        for(int i=1;i<=m;i++)
        {
            if(a[i]==1)
            {
                cout<<"No"<<endl;
            }
            else
            {
            if(b[a[i]]==0)
                cout<<"Yes"<<endl;
            else
                cout<<"No"<<endl;
            }
        }
        return 0;
    }
  • 相关阅读:
    redis应用场景
    java.lang.IllegalArgumentException: Result Maps collection already contains value for xxx
    Java问题解决:Java compiler level does not match the version of the installed Java project facet.
    win10 安装Oracle 11g release 2
    Oracle 11G Client客户端安装
    Oracle分页查询排序数据重复问题
    Mysql 函数使用记录(三)——UNIX_TIMESTAMP() 、UNIX_TIMESTAMP(date)
    PL/SQL Developer过期解决方法
    PL/SQL Developer登录出现——Using a filter for all users can lead to poor performance!
    Oracle Single-Row Functions(单行函数)——NULL-Related Functions
  • 原文地址:https://www.cnblogs.com/this-is-M/p/10672934.html
Copyright © 2011-2022 走看看