数论(一)(素数问题:埃拉托斯特特尼筛法,欧拉筛法)

                                                       素数问题

      咸鱼的一天。

素数(质数):除了1和它本身没有其他的因子;

合数:反之

原理:

1.算术基本定理:任何一个大于1的自然数 N,那么N可以唯一分解成有限个质数的乘积。
2. 若一个数可以进行因数分解,则得到的两个数一定是有一个>=sqrt(x),另一个<=sqrt(x)。

3.1-N内的素数的个数大约是logN。

素数主要有两个基本问题:

1.求1—n中的所有素数

2.判断一个数是否是素数
暴力写法:

#include<bits/stdc++>
#define MAXN 1e5;
bool isprime[MAXN];
bool is_prime(int x)
{
    int flag=0;
    for(int i=2;i<x;i++)
    {
        if(x%i==0)
        {
            flag++;
            break;
        }
    }
    if(flag) 
    {
        isprime[x]=false;
        return false;
    }
    else 
    {
        isprime[x]=true;
        return true;
    }
}

int init(int N)
{
    int cnt=0;    //记录素数的个数 
    for(int i=2;i<=N;i++)
    {
        if(is_prime(i))
            cnt++;
    }
    return cnt;
}

暴力复杂度过高不可取。O(n*sqrt(n))

筛法:
1.朴素筛:

初始所有偶数置为false,所有奇数置为true。所有奇数的倍数置为false。

扫描二维码关注公众号,回复: 3289291 查看本文章
//缺点:同一个数被不同因子筛了多次
#define MAXN 1e5
bool isprime[MAXN];
void init(int N)
{
    for(int i=2;i<=N;i++)
    {
        if(i%2==0)  isprime[i]=false;
        else        isprime[i]=true;
    }
    for(int i=3;i<=N;i++)
    {
        if(i%2!=0)
        {
            for(int j=2;j*i<=N;j++)
              isprime[j*i]=false;
        }
    }
}

2.埃氏筛

埃拉托斯特尼筛法,利用当前已经找到的素数,从后面的数中筛去当前素数的倍数。

原理:每个大于1的正整数n都可以表示成素数之积的形式。所以在1到n中一个数若不是素数,一定会被筛到。

复杂度:O(n*lglgn),近似为O(n)

缺点:某些数被每个质因子都筛了一遍导致速度减慢。

#define MAXN 1e5
bool isprime[MAXN];
void init(int N)      //求1到N中所有的素数
{
   memset(isprime,true,sizeof isprime);
   for(int i=2;i<=N;i++)               
   {
       if(isprime[i])          //2是素数,所以可以直接这样写
       {
           for(int j=2;i*j<=N;j++)
              isprime[i*j]=false;
       }
   }
}

3.欧拉筛

  和埃氏筛法的区别是对于每一个要筛除的数,欧拉筛法只筛除一次。

复杂度:O(n)

#include<bits/stdc++.h>
using namespace std;
const int MAXN=100000+5;
bool isprime[MAXN];//isprime[]表示i是不是质数 
int prime[MAXN], tot;//prime[]用来存质数 
void init(int N)
{
    memset(isprime,true,sizeof(isprime)/sizeof(bool)*N);  //初始化所有的数为质数
    for(int i=2;i<=N;i++)
    {
        if(isprime[i]) 
          prime[tot ++] = i;//把质数存起来 
        for(int j=0;j<tot&&i*prime[j]<=N;j++)
        {
            isprime[i*prime[j]]=false;
            if(i%prime[j]==0)  break;//保证每个合数被它最小的质因数筛去 
        }
    }    
}

总结:

朴素筛和埃筛区别:

朴素筛:把1-N内每个奇数的倍数给筛一遍

埃筛:把1-N内每个素数的倍数给筛一遍

1-N内奇数大于素数,所以数据量一大,时间差别明显。

埃筛和欧拉筛复杂度其实相差不是很多,更推荐埃筛,毕竟好写很多。

素数测定:

定理:若一个素数N不能被sqrt(N)下的所有素数整除,该数是素数

Lucas-Lehmer判定(会套板子就行)

Miller判断(会套板子就行)

猜你喜欢

转载自blog.csdn.net/hzaukotete/article/details/81103528
今日推荐