素数筛法总结

目录

朴素算法:判断一个数是否为素数?

当然肯定有更好的算法(更好背 :) )那就是埃拉托斯特尼筛法。简称埃氏筛法。

 那么还有一个算法就是欧拉筛。

素数筛法简而言之就是将素数筛出的算法,将其他的数给筛掉。这篇博客就总结几个常见的算法模板。

朴素算法:判断一个数是否为素数?

作为大佬的你来说肯定不用解释,下面是代码 

#include <bits/stdc++.h>

using namespace std;

using ll = long long;

bool ispri(int x)
{
    for(int i=2;i<=x;i++) if(x%i==0) return true;
    return false;
}
int main()
{
    int n;
    if(ispri(n)) cout << "Yes";
    else cout << "No";
    return 0;
}

还有一个小小的优化:就是当一个数有一个因子的时候,那么一定有一个对应的因子。

 像我这样的蒟蒻都明白,作为大佬的你来说轻轻松松。

所以我们就可以优化(其实不优化也可以),我们将搜索范围调小至2到根号n。

bool ispri(int x)
{
    for(int i=2;i*i<=x;i++) if(x%i==0) return true;
    return false;
}

 damn是,这个算法就是逊啦,如果要求n以内的所有素数呢?

当然肯定有更好的算法(更好背 :) )那就是埃拉托斯特尼筛法。简称埃氏筛法

核心思想用一个数组is_prime,来记录i是否是素数——is_prime[i]==1表示不是素数。

同样我们只用筛至平方根处

下面是代码:

#include <bits/stdc++.h>

using namespace std;

using ll = long long;

const int N = 1e6+5;
vector<int> prime;
bool is_prime[N];

void Eratosthenes(int n)
{
    for (int i = 2; i*i<= n; ++i) { //筛至平方根处
        if (!is_prime[i]) {
            prime.push_back(i);//i没有被筛掉,那么i为素数,将其放入prime数组
            if (i * i > n) continue;//防止越界
            for (int j = i * i; j <= n; j += i)
                is_prime[j] = true;// 是 i 的倍数的均不是素数
            // 因为从 2 到 i - 1 的倍数我们之前筛过了
            // 这里直接从i的倍数开始,提高了运行速度   
        }
    }
}
int main()
{
    int x;
    cin >> x;
    Eratosthenes(x);
    for(auto p : prime){
        cout << p << ' ';
    }
    return 0;
}


聪明的你一定会发现如果i==2,那么就会筛到6,如果i==3,那么也会筛到6

怎么办馁? 

 那么还有一个算法就是欧拉筛。

核心思想:我们只让一个数的最小质因子去筛它,例如12的质因子有2,3我们就让2去筛。

所以我们仍然用一个数组记录质因子,当我们要尝试用j去筛数的时候,判断i是否为j的倍数,换而言之,j是否为i的最小质因子。如果不是,那么这个数就被筛过了,就返回。

下面是程序:

#include <bits/stdc++.h>
// #define IOS std::ios::sync_with_stdio(false), std::cin.tie(nuintptr)
using namespace std;
using ll = long long;
const int N = 1e6+5;
vector<int> prime;
bool is_prime[N];
void Eulersieve(int n)
{
    for(int i=2;i<=n;++i){
        if(!is_prime[i]){
            prime.push_back(i);
        }
        for(int j : prime){
            if(i*j>n) break;
            is_prime[i*j] = true;
            if(i % j == 0) break; //欧拉筛的优化核心
        }
    }
}
int main()
{
    int x;
    cin >> x;
    Eulersieve(x);
    for(auto p : prime){
        cout << p << ' '; 
    }
    return 0;
}

OK了,想必你一定看懂了。来写一道题吧:

分解质因子 3 - 洛谷

 很容易看出来,如果用暴力会超时,我们就可以考虑素数筛法。

思路:这道题目可以使用欧拉筛来做,我们预处理1e8以内的数的最小质因子,这样我们就可以短时间内处理,举个例子:一个数为60.

AC CODE:

#include <bits/stdc++.h>
// #define IOS std::ios::sync_with_stdio(false), std::cin.tie(nuintptr)
using namespace std;
using ll = long long;
const int N = 1e8+5;
int miny[N];
vector<int> pri;
bool not_prime[N];
void pre(int n)
{
    for(int i=2;i<=n;++i){
        if(!not_prime[i]){
            pri.push_back(i);
            miny[i] = i; //假设素数的最小质因子是它本身
        }
        for(int j : pri){
            if(i*j>n) break;
            not_prime[i*j] = true;
            miny[i*j] = j; //i*j的最小质因子是j
            if(i % j == 0) break;
        }
    }
}
int main()
{
    int t;cin >> t;
    pre(N-5);
    while(t--){
        int n;
        cin >> n;
        int ans = 0;
        while(n!=1){
            ans^=miny[n];
            n/=miny[n];
        }
        cout << ans << endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值