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

来源:互联网 发布:网络悬疑剧两小无猜 编辑:程序博客网 时间:2024/05/02 00:34

一,素数

素数又称质数,有无限个。除了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

32 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;
}






0 0