一、试除法求质数

1、思路

想要判断一个数n是否是质数,最暴力的方法是从1到n-1遍历,如果有一个数能将n整除,就代表n不是质数
我们可以发现,对于n来说,n的最大的一个因数不会超过根号n,即i*i<=n。
所以我们只用枚举到根号n即可
时间复杂度为O(根号n)


2、代码模板:


#include<iostream>
using namespace std;

bool su(int x)
{
    if(x<2)
        return 0;
    for(int i=2;i<=x/i;i++)
    {
        if(x%i==0)
            return 0;
    }
    return 1;
}
int n;
int main()
{
    scanf("%d",&n);
    while(n--)
    {
        int x;
        scanf("%d",&x);
        if(su(x))
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}


二、埃氏筛法

1、思路

当我们从小到大遍历到每个数时,直接把这个数的倍数全部筛掉。
时间复杂度为O(nlogn)
对于判断一个数字是否是素数有点慢
这个算法用来判断从1到n的所有质数。

对于朴素法埃氏筛来说,还有个优化版,因为每个合数都能分解为质数的积,所有我们只用把质数的倍数筛掉,这样可以避免一个数被重复筛掉
如6会被2和3重复筛掉。
优化版埃氏筛时间复杂度为O(nloglogn
比朴素版快了3倍

2、代码模板:

朴素法埃氏筛:


#include<iostream>

using namespace std;

const int N=1e6+10;

int n,cnt;//cnt用来存下标
int primes[N];//记录所有质数
bool st[N];//0代表是质数。1代表不是质数

int main()
{
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
    {
        if(!st[i])//如果i是质数
            primes[cnt++]=i;
        for(int j=1;j<=n/i;j++)
            st[i*j]=1;//倍数标记为合数
    }
    printf("%d",cnt);
    return 0;
}


优化版埃氏筛法


#include<iostream>

using namespace std;

const int N=1e6+10;

int n,cnt;//cnt用来存下标
int primes[N];//记录所有质数
bool st[N];//0代表是质数。1代表不是质数

int main()
{
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
    {
        if(!st[i])//如果i是质数
        {
            primes[cnt++]=i;
            for(int j=1;j<=n/i;j++)
                st[i*j]=1;//倍数标记为合数
        }
    }
    printf("%d",cnt);
    return 0;
}




三、线性筛(最快)

1、思路

每一个合数都会被它的最小质因子筛掉。
速度比优化版的埃氏筛快1倍


2、代码模板:


#include<iostream>

using namespace std;

const int N=1e6+10;

int n,cnt;//cnt用来存下标
int primes[N];//记录所有质数
bool st[N];//0代表是质数。1代表不是质数

int main()
{
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
    {
        if(!st[i])
            primes[cnt++]=i;
        for(int j=0;primes[j]<=n/i;j++)
        {
            st[primes[j]*i]=1;//将质数的倍数标记为合数
            if(i%primes[j]==0)//当primes[j]是i的最小质因子时跳出
                break;
        }
    }
    printf("%d",cnt);
    return 0;
}


四、6倍原理

1、思路

除了2和3,每一个质数,都在6的倍数的左右,
时间复杂度和时除法差不多,比试除法快一点点

2、代码模板:


#include<iostream>
using namespace std;
bool su(int x)
{
    if(x<2)
        return 0;
    if(x==2||x==3)//2,3特判
        return 1;
    if(x%6!=1&&x%6!=5)//当x不为6左右两边的数时就不是质数
        return 0;
    
    for(int i=5;i<=x/i;i+=6)
    {
        if(x%i==0||x%(i+2)==0)
            return 0;
    }
    return 1;
}
int n;
int main()
{
    scanf("%d",&n);
    while(n--)
    {
        int x;
        scanf("%d",&x);
        if(su(x))
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}




五、分解质因数

1、原理

和试除法差不多,每次遇到质因数就一直除直到不能整除再换下一个
时间复杂度为O(根号n)
n最多有一个大于根号n的质因子。

2、代码模板:


#include<iostream>

using namespace std;

int n;
int main()
{
    scanf("%d",&n);
    while(n--)
    {
        int x;
        scanf("%d",&x);
        for(int i=2;i<=x/i;i++)
        {
            int sum=0;
            if(x%i==0)
            {
                while(x%i==0)
                {
                    x/=i;
                    sum++;
                }
                printf("%d %d\n",i,sum);
            }
        }
        if(x>1)
            printf("%d 1\n",x);
        printf("\n");
    }
    return 0;
}