判断素数 和素数筛(埃筛和欧拉筛)
素数判断· 根据素数的定义,只含有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;
}
}