埃拉特斯特尼篩法(埃氏篩)
原理:
當一個數是素數的時候,那麼他的倍數肯定是合數。時間複雜度爲 O(nloglogn)。
int isprime[MAXN];
int vis[MAXN];
void Prime(int n)
{
int cnt = 0;
memset(vis, 0, sizeof(vis)); //vis裏0是素數,1是合數
vis[0] = 1;
vis[1] = 1;
for (int i = 2; i < n; i++){
if (!vis[i]){
isprime[cnt++] = i; //保存素數
for (int j = i * i; j < n; j += i){
vis[j] = 1; //不是素數
}
}
}
}
歐拉篩
原理:
首先,任何合數都能表示成一系列素數的積。然後利用了最小的素數因子,每個合數僅被它的最小素因子篩去正好一次。
時間複雜度爲 O(n)。
int isprime[MAXN]; //保存素數
int vis[MAXN]; //初始化
void eulerSieve(int n)
{
int cnt = 0;
memset(vis, 0, sizeof(vis)); //0是素數,1是合數
for (int i = 2; i < n; i++){
if (!vis[i])
isprime[cnt++] = i;
for (int j = 0; j < cnt && i * isprime[j] < n; j++){
vis[i * isprime[j]] = 1;
if (i % isprime[j] == 0)
break;
}
}
}
理解的難點就在於這一句
if (i % isprime[j] == 0) break;
這一句保證每個數只被它的最小質因子被篩一次,
對於一個數 a 假設它可以整除 isprime[ j ],
即 a = isprime[ j ] * x,
那麼 a * isprime[ j + 1 ] = isprime[ j ] * x * isprime[ j+1 ],
所以 j 再往後就沒有必要篩了,
因爲 a * isprime[ j + 1 ] 肯定會在 i = x * isprime[ j + 1 ] 的時候被 isprime[ j ] 篩掉。