质数学习笔记

定义

若一个自然数无法被除了1和它自身之外的任何自然数整除,则称这个数为质数(又称素数)。
在整个自然数集合中,质数分布不多,分布稀疏,对于一个足够大的自然数N,不超过N的质数大约有N/lnN个,即每lnN个数中大约有一个质数。

质数的判定

试除法

   若一个正整数为合数,则存在一个能整除N的数T,其中2$\leq$T$\leq$N。证明就略了吧。
根据以上命题,我们只需要扫描2~$\sqrt{N}$之间的所有整数,依次检查它们能否整除N,若都不能整除,则N是质数,否则是合数。时间复杂度为O($\sqrt{N}$)。

void primes(int n)
{
    memset(v,0,sizeof(v));
    for(int i=2;i<=n;i++)
    {
        if(v[i]) continue;
        cout<<i<<endl;
        for (int j = i; j < n/i; j++)
            v[i*j]=1;
    }
}

还有一种Miller-Robbin判定法,是一种随机算法,效率更高,我马上去学。

质数的筛选

这里就介绍几种筛选质数的方法。

Eratosthenes筛法

任意整数x的倍数,都必定不是质数。
我们可以从2开始,有小到大扫描每个数,再扫描这个数的倍数,标记为合数,当扫描到一个数时,若它没有被标记,则它不能被2~N-1的数整除,它就是素数。
还有就是小于$x^2$的数已经被更小的数标记过了,因此,我们可以进行优化,从$x^2$开始标记倍数。

void primes(int n)
{
    memset(v,0,sizeof(v));
    for(int i=2;i<=n;i++)
    {
        if(v[i]) continue;
        cout<<i<<endl;
        for (int j = i; j < n/i; j++)
            v[i*j]=1;
    }
}

埃氏筛法时间复杂度为O(NloglogN)。

线性筛法

线性筛法是一种比埃氏筛法更优的筛法。它通过“从小到大累积质因子”的方式标记每个合数,使得合数的标记方式进一步压缩,提高了效率。设数组v记录每个数的最小质因子,按照以下步骤维护v:

  1. 依次考虑2~N之间的每个数i。
  2. 若v[i]=i,说明i是质数,把它保存下来。
  3. 扫描不大于v[i]的每个质数p,令v[i$\times$p]=p。也就是再i的基础上再累积一个质因子p。因为p$\leq$v[i],所以p就是合数p$\times$i的最小质因子。
    时间复杂度O(N)。
void primes(int n)
{
    memset(v,0,sizeof(v)); //最小质因子
    m=0; //质数数量
    for (int i = 2; i <= n; i++)
    {
        if (v[i]==0)
        {
            v[i]=i;
            prime[++m]=i;  //i是质数
        }
        for (int j = 0; j <= m; j++)
        {
            if(prime[j]>v[i]||prime[j]>n/i) break;  //质数的范围不能超出v[i]和n
            v[i*prime[j]]=prime[j];
        }
    }
}

质因数分解

算数基本定理

任何一个大于1的正整数都能被唯一分解为有限个质数的乘积,可写作:

N=p_1^{c_1}p_2^{c_2}...p_m^{c_m}

其中$c_i$都是正整数,$p_i$都是质数,且满足:

p_1<p_2<...<p_m

试除法

这种方法结合了质数判定的“试除法”和“埃氏筛法”。
扫描2~$\sqrt{N}$中的每个整数d,若d能乘除N,则从N中除掉所有的因子d,同时累积除掉的d的个数。
因为每个因子都是第一次扫描到这个因子是就被完全除掉了,所以时间复杂度为O(N)。

void divide(int n)
{
    m=0;
    for (int i = 2; i <= sqrt(n); i++)
    {
        if (n%i==0)  //这里i一定是质数,因为后面搜到合数时,早已被前面的质数除掉了
        {
            p[++m]=i,c[m]=0;
            while(n%i==0)
            {
                n/=i;
                c[m]++;
            }
        }
    }
    if (n>1)  //n是质数
    {
        p[++m]=n;
        c[m]=1;
    }
}

还有一个“Pollard's Rho”算法,比试除法高效。

猜你喜欢

转载自www.cnblogs.com/zxj-hans/p/11261148.html