当前位置:   article > 正文

质数——数学知识(c++)_c++质数

c++质数

一、定义

若一个正整数无法被除1和它自身以外的自然数整除,则该数为质数(或素数),否则该数为合数。
1既不是质数也不是合数
由定义可得质数的一个性质:只有1和它本身两个因数。
补充:对于一个足够大的整数N,不超过N的质数大约有N/㏑N个。即每㏑N个数中有1个质数。

二、判定质数

根据定义:素数就是一个数除了1 和他本身没有其他因数的数叫做质数。
于是我们对于一个N,可以可以从2枚举到N−1,从而判断这个数是不是质数。

bool Is_prime(int n){
    if(n==1) return false;
    if(n==2) return truefor(int i=2;i<n;i++) 
    	if(n%i==0) return false;
    	return true;	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

时间复杂度O(n);
对于上述程序显然不能满足我们的需求,如N较大时,这样的程序肯定容易超时,要想办法优化以上程序。

优化

我们不难发现N的因数是成对出现的,所以对于任何一个整数N,我们只需要从1枚举到sqrt(N)就可以了。
于是代码如下:

bool is_prime(int x)
{
    if (x < 2) return false;
    for (int i = 2; i <= x / i; i ++ )//
        if (x % i == 0)
            return false;
    return true;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

时间复杂度o(sqrt(n))
ps.关于i<=n/i : 如果当i很大,还直接计算i*i时,可能会爆int,而计算n/i就没有这个问题。

经典例题

AcWing 866. 试除法判定质数
给定n个正整数ai,判定每个数是否是质数。

输入格式
第一行包含整数n。

接下来n行,每行包含一个正整数ai。

输出格式
共n行,其中第 i 行输出第 i 个正整数ai是否为质数,是则输出“Yes”,否则输出“No”。

数据范围
1≤n≤100,
1≤ai≤2∗109
输入样例:

2
2
6
  • 1
  • 2
  • 3

输出样例:

Yes
No
  • 1
  • 2
#include <iostream>
#include <algorithm>

using namespace std;

bool is_prime(int x)
{
    if (x < 2) return false;
    //列出i较小的因数
    for (int i = 2; i <= x / i; i ++ )//且是i的因数  
        if (x % i == 0)
            return false;
    return true;
}

int main()
{
    int n;
    cin >> n;

    while (n -- )
    {
        int x;
        cin >> x;
        if (is_prime(x)) puts("Yes");
        else puts("No");
    }

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

三、分解质因素

任何一个大于1的自然数 N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积,即:在这里插入图片描述

这里P1<P2<P3…<Pn均为质数,其中指数ai是正整数。
这里有个性质:n中最多只含有一个大于sqrt(n)的因子。证明通过反证法:如果有两个大于sqrt(n)的因子,那么相乘会大于n,矛盾。证毕
于是我们发现最多只有一个大于sqrt(n)的因子,对其进行优化。先考虑比sqrt(n)小的,代码和质数的判定类似
最后如果n还是>1,说明这就是大于sqrt(n)的唯一质因子,输出即可。

试除法

我们可以扫描2~sqrt(N)之间的每一个整数d,若d能整除N,则从N中除掉所有的因子d,同时累计除去的d的个数。

因为一个合数的因子一定在扫描到这个合数之前就从N中被除掉了,所以在上述过程中能整除N的一定是质数,最终就得到了质因数分解的结果,易知时间复杂度为O(sqrt(N))。

特别的,若N每有被任何2~sqrt(N)的数整除,则N是质数,无需分解。

时间复杂度: o(n) --> o(sqrt(n))

void divide(int x)
{
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)//一定为质因子
        {
            int s = 0;//求质数的次数. 
            while (x % i == 0) x /= i, s ++ ;//是否能被再次整除.
            cout << i << ' ' << s << endl;
        }
         //特判, 如果不是1那么就是那个较大的质因子.
        //最多只有一个大于sqrt(n)的质因子.
    if (x > 1) cout << x << ' ' << 1 << endl;
    cout << endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

经典例题

AcWing 867. 分解质因数
给定n个正整数ai,将每个数分解质因数,并按照质因数从小到大的顺序输出每个质因数的底数和指数。

输入格式
第一行包含整数n。

接下来n行,每行包含一个正整数ai。

输出格式
对于每个正整数ai,按照从小到大的顺序输出其分解质因数后,每个质因数的底数和指数,每个底数和指数占一行。

每个正整数的质因数全部输出完毕后,输出一个空行。

数据范围
1≤n≤100,
1≤ai≤2∗109
输入样例:

2
6
8
  • 1
  • 2
  • 3

输出样例:

2 1
3 1

2 3
  • 1
  • 2
  • 3
  • 4
#include <iostream>
#include <algorithm>

using namespace std;

void divide(int x)
{
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
        {
            int s = 0;
            while (x % i == 0) x /= i, s ++ ;
            cout << i << ' ' << s << endl;
        }
    if (x > 1) cout << x << ' ' << 1 << endl;
    cout << endl;
}

int main()
{
    int n;
    cin >> n;
    while (n -- )
    {
        int x;
        cin >> x;
        divide(x);
    }

    return 0;
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

四、筛质数

AcWing 868. 筛质数
给定一个正整数n,请你求出1~n中质数的个数。

输入格式
共一行,包含整数n。

输出格式
共一行,包含一个整数,表示1~n中质数的个数。

数据范围
1≤n≤106
输入样例:

8
  • 1

输出样例:

4
  • 1
朴素筛法

把从2~n中的从小到大一次删掉每个数的倍数

#include <iostream>
#include <algorithm>

using namespace std;

const int N= 1000010;

int primes[N], cnt;// primes[]存储所有素数
bool st[N];// st[x]存储x是否被筛掉

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (st[i]) continue;
        primes[cnt ++ ] = i;
        for (int j = i + i; j <= n; j += i)
            st[j] = true;
    }
}

int main()
{
    int n;
    cin >> n;

    get_primes(n);

    cout << cnt << endl;

    return 0;
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
埃氏筛法

只把质数的倍数删掉

#include <iostream>
#include <algorithm>

using namespace std;

const int N= 1000010;

int primes[N], cnt;// primes[]存储所有素数
bool st[N];// st[x]存储x是否被筛掉

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) {
        primes[cnt ++ ] = i;
        for (int j = i + i; j <= n; j += i)//将i的所有倍数删掉(循环放在里面)
            st[j] = true;
           }
    }
}

int main()
{
    int n;
    cin >> n;

    get_primes(n);

    cout << cnt << endl;

    return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
线性筛法
//算法核心:x                  仅会被其最小质因子筛去
#include <iostream>
#include <algorithm>

using namespace std;

const int N= 1000010;

int primes[N], cnt; // primes[]存储所有素数
bool st[N];// st[x]存储x是否被筛掉

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        //假设primes[0]为n最小的质因子,i为最大的因数,
        //易知若primes[i]中i>0,则会进入循环后产生多余的标记。
        for (int j = 0; primes[j] <= n / i; j ++ )//对于任意一个合数x,假设pj为x最小质因子,当i<x/pj时,一定会被筛掉
        {
            //标记;primes[j]一定是primes[j]*i的最小质因子
            st[primes[j] * i] = true;
            //表明primes[j]一定是i的最小质因子,没有必要再遍历,primes要小于等于i的最小质因子
            //这样能保证每个数遍历一遍,而没有重复
            if (i % primes[j] == 0) break;
             /*
            1.i%pj == 0, pj定为i最小质因子,pj也定为pj*i最小质因子
            2.i%pj != 0, pj定小于i的所有质因子,所以pj也为pj*i最小质因子
            */
        }
    }
}

int main()
{
    int n;
    cin >> n;

    get_primes(n);

    cout << cnt << endl;

    return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/75321
推荐阅读
相关标签
  

闽ICP备14008679号