「AcWing学习记录」质数

AcWing 866. 试除法判定质数

原题链接

时间复杂度\(O(\sqrt{n})\)

\[d|n\implies\cfrac{n}{d}|n \]

\[d\leq\cfrac{n}{d}\implies d^2\leq n\implies d\leq \sqrt{n} \]

#include<iostream>
#include<algorithm>

using namespace std;

bool is_prime(int n)
{
    if(n < 2) return false;
    for(int i = 2; i <= n / i; i++)
        if(n % i == 0)
            return false;
    return true;
}

int main()
{
    int t;
    scanf("%d", &t);

    while(t--)
    {
        int a;
        scanf("%d", &a);
        if(is_prime(a)) puts("Yes");
        else puts("No");
    }

    return 0;
}

AcWing 867. 分解质因数

原题链接

时间复杂度介于\(O(\log{n})\)\(O(\sqrt{n})\)之间

#include<iostream>
#include<algorithm>

using namespace std;

void divide(int n)
{
    for(int i = 2; i <= n / i; i++)
        if(n % i == 0) //i一定是质数
        {
            int s = 0;
            while(n % i == 0)
            {
                n /= i;
                s++;
            }

            printf("%d %d\n", i, s);
        }

    if(n > 1) printf("%d %d\n", n, 1); //n中最多只包含一个大于sqrt(n)的质因子,可通过反证法证明
    puts("");
}

int main()
{
    int t;
    scanf("%d", &t);

    while(t--)
    {
        int a;
        scanf("%d", &a);

        divide(a);
    }

    return 0;
}

AcWing 868. 筛质数

原题链接

对于一个大于2的正整数p,如果p没有被筛掉,那么说明p不是2到p-1中任何一个数的倍数,即2到p-1中没有一个数是p的约数。

朴素筛法的时间复杂度计算

\[\cfrac{n}{2} + \cfrac{n}{3} + \cdots + \cfrac{n}{n} = n(\cfrac{1}{2} + \cfrac{1}{3} + \cdots + \cfrac{1}{n}) \]

\[\lim_{n \to \infty}(\cfrac{1}{2} + \cfrac{1}{3} + \cdots + \cfrac{1}{n}) = \ln n + C \]

C为欧拉常数,约为0.577

\[n\ln n < n\log_{2}{n} \]

时间复杂度可以记成\(O(n\log n)\)


埃氏筛法的时间复杂度计算
质数定理:1~n中有\(\cfrac{n}{\ln n}\)个质数

\[n(\cfrac{1}{2} + \cfrac{1}{3} + \cdots + \cfrac{1}{n}) = n\ln n / \ln n = O(n) \]

而真实的时间复杂度为\(O(n\log \log n)\)


线性筛法的原理
1.i % pj == 0
pj一定是i的最小质因子,pj一定是pj * i的最小质因子
2.i % pj != 0
pj一定小于i的所有质因子,pj也一定是pj * i的最小质因子

对于一个合数x,假设pj是x的最小质因子,当i枚举到x/pj的时候一定会被筛掉,所以任何一个合数都会被筛掉,并且只用最小质因子来筛,每个数只有一个最小质因子,所以每个数只会被筛一次,所以是线性的。

//朴素筛法
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1000010;

int primes[N], cnt;
bool st[N];

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) st[j] = true;
    }
}

int main()
{
    int n;
    scanf("%d", &n);

    get_primes(n);

    printf("%d\n", cnt);

    return 0;
}

//由于只有质数的倍数才需要筛掉,所以可以将筛选的循环放到判断里面去

//埃氏筛法
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) st[j] = true;
        }
    }
}

//埃氏筛法是筛掉质数的倍数,但仍会重复计算,线性筛法中每个合数只会被其最小质因子筛掉,解决了重复计算的问题

//线性筛法
void get_primes(int 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] = true;
            if(i % primes[j] == 0) break;
        }
    }
}
posted @ 2023-02-12 01:32  恺雯  阅读(36)  评论(0)    收藏  举报