您的位置:首页 > 其它

数论之素数,包括eratosthenes算法,欧拉函数

2017-01-21 10:29 483 查看
一,素数

素数又称质数,有无限个。除了1和它本身以外不再有其他的除数整除。

算术基本定理:每个大于1的自然数均可写为质数的积,而且这些素因子按大小排列之后,写法仅有一种方式。

例如:6936=2^3*3*17^2,1200=2^4*3*5^2。

二,质因数的分解

概念:把一个合数用素因数相乘的形式表示出来,叫做质因数分解。(注意:由于任何一个合数n至多会有一个大于根号n的因子)

一般我们用短除法分解素因数,算法步骤如下:

1.先用一个能整除这个合数的素数(通常从最小的开始)去除。

2.得出的商如果是合数,再按照上面的方法继续除下去,直到得出的商是素数为止。

3.然后把各个除数和最后的商按从小到大的顺序写成连乘的形式。

代码如下:cnt=0; //cnt表示素因子的个数

for(int i=2;i*i<=n;i++)//由于任何一个合数至多或有一个大于根号n的因子

{

        if(n%i==0)

        {

            ++cnt;

            p[cnt]=i;//p数组存的是素因子

            num[cnt]=0;//存的是每个素因子的指数

            while(n%i==0)

            {

                ++num[cnt];

                n/=i;

            }//while循环的目的是每次历经一个i,n都会进行更新,或者是有多个i,n也会进行更新

        }

}

    if(n>1)

    {

        ++cnt;

        p[cnt]=n;

        num[cnt]=1;

    }需要if循环的原因也是因为由于任何一个合数至多或有一个大于根号n的因子(例如n=10)

三,素数的测试

1,一般的思路

bool divisibiity_test(int n)

{

    for (int i=2; i<n; i++)

        if (n % i == 0)

            return false;   // 不是质数

    return true;    // 是质数

}

2,改进的方法

bool divisibiity_test(int n)

{

//一个数至少有一个比sprt(n)小的质因数。

      for (int i=2; i<=sqrt(n); i++)

        if (n % i == 0)

            return false;

    return true;

}

时间复杂度:O(sqrtN)

四,Eratosthenes筛法

代码如下:

1,

bool prime[20000000];

void eratosthenes()

{

    memset(prime,1,sizeof(prime));

    prime[0] = 0;  prime[1] = 0;  // 0 和 1 不是质数

    for (int i=2; i<20000000; i++)

        if (prime[i]==1) // 删掉质数i的倍数

           for (int j=i+i; j<20000000; j+=i)

                prime[j] = 0;

}

2,优化的如下:(优化的原因:删掉质数 i 的倍数时,早已删掉1 倍~ i-1 倍之间的合数了,所以直接从i倍开始删除)。

void eratosthenes(){

    memset(prime,1,sizeof(prime));

    prime[0] = 0;prime[1] = 0;

    for (int i=2; i<20000000; i++)

        if (prime[i]==1)

      //删掉i的倍数从i倍开始。

            for (int j=i*i; j<20000000; j+=i)

                prime[j] = 0;

}

五,欧拉函数

1.定理:

对正整数n,欧拉函数φ(phi)指是小于n的所有数中与之互质的个数(包含1)。如φ(8)=4,因为1,3,5,7均和8互质

2.表达形式:n=p1^a1*p2^a2....pk^ak(p1,p2...pk是素数)

3,计算公式:φ(n)=n*(1-1/p1)*(1-1/p2)*......*(1-1/pk)

例如:φ(8)=4有1,3,5,7,8=2^3, φ(8)=8*(1-1/2)=4.

     φ(10)=4有1,3,7,9 ,10=2*5,φ(10)=10*(1-1/2)*(1-1/5)=4.

4,性质:

a)当p为质数时, φ(p) = p – 1。

    证明:因为小于本身的数都与该数互质,但是注意φ(1)=1.

  b)对于互质的正整数a和n,有a^φ(n) ≡ 1 (mod n) (mod n的意思是两边同时%n).

  c)费马小定理:若正整数a 与素数p 互质,则有a^(p - 1)≡1 mod p。

    证明:由于性质a可知当p为质数,φ(p) = p -1,代入性质b即可证明。

d)当n为奇数时φ(2n)=φ(n).

  e)当n和m互质时,φ(n*m)=φ(n)*φ(m).

  f)若n=p^k(p为质数),φ(n)=p^k-p^(k-1).

    证明:因为除了p的倍数外,其他数都跟n互质。

朴素算法实现:

1.根据公式1:n=p1^k1*p2^k2*…*pr^kr和公式2:φ(n)=n* (1-1/p1) *…* (1-1/pr)。

2.可将公式2可拆成n* (1-1/p1)=n-n/p1计算。

代码实现:

int euler(int n)

{

    int i,ans=n;

    for(i=2; i*i<=n; i++)

        if(n%i==0)

        {

            ans=ans-ans/i;

            do

                n/=i;//把该素因子全部约掉

            while(n%i==0);

        }

    if(n>1)

        ans=ans-ans/n;

    return ans;

}

例题:

1286.有多少素数

Time Limit: 1000 MS    Memory Limit: 32768 KB

Total Submission(s):
319    Accepted Submission(s):
44

Description

给你很多的正整数,只是为了找出有多少素数。

Input

有很多的测试用例,每个测试用例第一行是正整数N,表示要从N个整数中找。每个整数不超过2147483647,其中每个不小于2。

Output

对于每种情况输出素数的个数。

Sample Input

3
2 3 4


Sample Output

2


(已经AC过的代码)

#include<cstdio>

#include<iostream>

#include<cmath>

using namespace std;

int IsPrimeNumber(int n)

{

    if (n==2)

    {

        return true;

    }

    if (n%2==0)

    {

        return false;

    }

    int sqrtn=(int)sqrt((double)n);

    bool flag=true;

    for (int i=3; i<=sqrtn; i+=2)

    {

        if (n%i==0)

        {

            flag=false;

        }

    }

    return flag;

}

int main()

{

    int m,n,x;

 while(scanf("%d",&m)!=EOF)

    {

        int sum=0;

        for(int k=0; k<m; k++)

        {

            scanf("%d",&n);

            x=IsPrimeNumber(n);

            if(x)

                sum++;

        }

        cout<<sum<<'\n';

    }

    return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: