数论基础判断素数

            判断素数 和素数筛(埃筛和欧拉筛)

素数判断· 根据素数的定义,只含有1和本身的因数的数被称为素数,由此定义枚举小于这个数的所有数,如果出现能够整除的,说明这个数不是质数。注意:此处只需要枚举到sqrt(k)。因为 若 i | k,则 k/i | k所以i如果不是因数,那么k/i也不是,最多到sqrt(k),超过这个范围就没有意义了。O(sqrt(n))此处两数相乘采用逆元,可以防止爆int

int is_prime(int k) {//判断k是否是质数

    int ok = 1;

    if (k < 2)return 0;

    for (int j = 2; j <= k / j; j++) {//枚举到sqrt(k)

        if (k % j == 0) {

            ok = 0;

            return 0;

        }

    }

    return 1;

}

1.埃筛的思想比较简单,一个数的所有倍数都不可能是质数所以,枚举当前数的范围内所有倍数,将他们删去,剩下的都是质数。同时可以简单优化一下,由惟一分解定理,只需要筛去质数,合数也就会被顺带筛去。所以枚举质数的倍数即可。优化后复杂度O(nloglog)\n\n        2.欧拉筛也叫做线性筛。他保证每次筛的时候只会通过一个质因数将一个合数筛去,而不像埃筛那样重复筛同一个数好多次。\n\n其主要的优化有两方面:\n\n①每次只枚举质数的倍数。\n\n②保证prime[i]是某个被筛去的合数的最小质因数.\n\n重点在第二点。因为我们是从小到大枚举的质数,那么当第一次满足判断的数j,j%prime[i]==0那么这个prime[i]就是j的最小质因数,同时也是prime[i]*j的最小质因数。同时,因为prime[i]是j的最小质因数,那么prime[i]也会是之后prime[i+1~size]*j这些合数的最小质因数

#include<bits/stdc++.h>

using namespace std;

#pragma warning(disable:4996);

//#define int long long 

#define rep(j,b,e) for(int j=(b);j<=(e);j++)

#define drep(j,e,b) for(int j=(e);j>=(b);j--)

const int N = 1e8 + 10;

int T = 1;

int n, m, k;

int gcd(int a, int b) {

 return a % b == 0 ? b : gcd(b, a % b);

}

vector<int>prime;

int NotisPrime[N];//1表示不是一个质数

void GetPrime_Era(int n) {//会多次标记同一个值

 rep(j, 2, n) {

  if (NotisPrime[j] == 0) {//如果是质数

   prime.push_back(j);

   for (int i = j; i <= n/j; i++)//质数的倍数全是合数,逆元写成/j防止爆int

    NotisPrime[i * j] = 1;

  }

 }

}

void GetPrime_Ola(int n) {//效率更高,一个数只会被他的最小质因数筛掉

 rep(j, 2, n) {

  if (NotisPrime[j] == 0)//筛完还是素数就加入

   prime.push_back(j);

  for (int i = 0; i < prime.size() && prime[i] <= n/j; i++) {//逆元枚举质数,筛pi*j

   NotisPrime[j * prime[i]] = 1;

 

   if (j % prime[i] == 0)break;//保证prime[i]是这个合数的最小质因数

  }

 }

}

signed main() {

#ifndef ONLINE_JUDGE

 freopen("out.txt", "w", stdout);

#endif

 ios::sync_with_stdio(0); cout.tie(0);

 int q;

 cin >> n >> q;

 GetPrime_Ola(n);

 rep(j, 1, q) {

  cin >> k;

  cout << prime[k - 1] << endl;

 }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值