素数筛

素数筛

暴力法

对于一个数字x,可以从2枚举到n-1,进行mod运算时间复杂度为O(n)

#include<stdio.h>
bool findprime(int x)
{
    if(x==1) return false;
    if(x==2) return true;
    for(int i = 2;i<x;i++)
    {
        if(x%i==0)
            return false;
        
    }
        
    return true;

}
int main()
{
    long long n,m;
    long long a;
    scanf("%lld %lld",&n,&m);
    while(m--)
    {
        scanf("lld",&a);
        if(findprime(a))
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}

暴力优化.:1. for 循环里面的 i<n改成 i<=sqrt(n) O(sqrt(n)/3)

因为一个数可以写成两个数相乘的形式 这两个数可以颠倒位置,结果相同因为for 循环从小的开始到大的结束,所以不用遍历到较大的因子以减少运算量。

  1. 利用判断(根据素数的规律):大于等于5的质数一定和6的倍数相邻,例如5 and 7,11 and 13,17 and 19,
    令 x≥1 , 将 大 于 等 于 55 的 自 然 数 表 示 如 下 : …6x1,6x,6x+1,6x+2,6x+3,6x+4,6x+5,6(x+1),6(x+1)+1…
    可以看到,不在6的倍数两侧,即6x两侧的数为6x+2,6x+3,6x+4…由于2(3x+1),3(2x+1),2(3x+2),
    所以它们一定不是素数,再除去6x本身,显然,素数要出现只可能出现在6x的相邻两侧。
    所以,基于以上条件,我们假如要判定的数为n,则n必定是6x-1或6x+1的形式,对于循环中6i-1, 6i,6i+1,6i+2,6i+3,6i+4,其中如果n能被6i,6i+2,6i+4整除,则n至少得是一个偶数,
    但是6x-1或6x+1的形式明显是一个奇数,故不成立;另外,如果n能被6x+3整除,则n至少能被3整 除,
    但是6x能被3整除,故6x-1或6x+1(即n)不可能被3整除,故不成立。综上,循环中只需要考虑6i-1 和6i+1的情况

    时间复杂度为 O(sqrt(n)/3)

    bool findprime(int x)
    {
        if(x==1)
            return false;
        if(x==2 || x==3)
            return true;
        if(x % 6 !=1 && x%6 !=5)
            return false;
        for(int i=5;i<sqrt(x);i+=6)
        {
            if(x%i==0 || x(i+2)==0)
                return false;
            
        }
        return true;
        
        
    }
    

埃氏筛

基本思想 :素数的倍数一定不是素数。

利用已经找到的素数,从后面书中筛去当前素数的倍数,由算数基本定理可得,当前菽粟已经是晒取数的质因子,如此下去能筛出所有操作之后的合数,是一种比较快的筛法。

先把 2 表上 true 然后把2-100中2的倍数标位false,再把三标为true,把三的倍数标位false,重复操作完成检索。、

//某区间内有多少个素数 
int prime[maxn] ; //存素数
bool is_prime[maxn] ;  //存是否是素数
int isPrime(int x) 
{    memset(is_prime , true , sizeof(is_prime)) ;  //注意初始化    
 int p = 0 ; //计数器   
 is_prime[0] = false ;   
 is_prime[1] = false ;  //0 , 1 不是素数   
 for(int i = 2 ; i <= x ;++ i) 
 {       
     if(is_prime[i])  
         
 {          
          prime[p ++] = i ;
  for(int j = 2 * i ; j <= x ; j += i )  //如果i是素数,那么让i的所有 倍数都不是素数               
      is_prime[j] = false ;     
 }
     return p ;  //返回素数的个数 
 }    

时间复杂度为 O(nloglogn)

但是研究上述代码,我们可以发现这个方法可以继续优化,因为在埃氏筛中,有的数字会因为有多个因 数而被筛很多次,例如30会被2,3,5筛,导致计算冗余,下面我们可以对埃氏筛进行改进,从而得到欧式筛

这个方法可以保证每个合数在N/M的最小素因子时被筛出,所以时间复杂度仅为O(N)
已经可以满足大部分需求,在竞赛中,这种方法也可以在极短的时间内求出关于N的质数表。
思想:最小质因数 * 最大因数(非自己) = 这个合数

//某区间有多少个素数
int prime[maxn];
bool boo[maxn];
int findprime(int x)
{int p=0;
memset (book,true,sizeof(book));
book[0]=false;
book[1]=false;
for(int i=2;i<=x;i++)
{
	if(book[i])
{
		prime[p++]=i;
}
for(int j=0;j<p &&prime[j]*i<=x;j++)
{
book[prime[j]*i]=false}
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Klaus1205

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值