從前有一個素數篩法叫埃拉託斯特尼篩法,它的思想很簡單,把1-n以內素數的整數倍的數字劃掉,留下的就全是素數,但是它的複雜度是O(NlglgN),對於大量不友好數據會跪,於是線性曬登場了。
#include <cstring>
using namespace std;
int prime[1100000],primesize,phi[11000000];
bool isprime[11000000];
void getlist(int listsize)
{
memset(isprime,1,sizeof(isprime));
isprime[1]=false;
for(int i=2;i<=listsize;i++)
{
if(isprime[i])prime[++primesize]=i;
for(int j=1;j<=primesize&&i*prime[j]<=listsize;j++)
{
isprime[i*prime[j]]=false;
if(i%prime[j]==0)break;
}
}
}
以上就是線性曬代碼,他與埃氏篩法大概有這麼幾點不同:
①:if(i%prime[j]==0)break;
這句代碼保證了每個數最多被篩一次,將時間複雜度降到了線性。
證明如下:prime[]數組中的素數是遞增的,當i能整除prime[j],那麼i*prime[j+1]這個合數肯定被prime[j]乘以某個數篩掉。
因爲i中含有prime[j],prime[j]比prime[j+1]小,即i=k*prime[j],那麼i*prime[j+1]=(k*prime[j])*prime
[j+1]=k’*prime[j],接下去的素數同理。所以不用篩下去了。因此,在滿足i%prime[j]==0這個條件之前以及第一次
滿足改條件時,prime[j]必定是prime[j]*i的最小因子。
大名鼎鼎的線性曬日常篩素數的速度大概是埃氏篩的3-4倍,然而在小數據中卻有被完爆的可能QAQ
所以歐拉篩法不只是拿來篩個素數,更重要的一點是線性篩可以用來求解積性函數。
積性函數f(x)應滿足f(a×b)=f(a)×f(b),a與b應互素。而完全積性函數則應滿足對於任意的a與b,前面的等式應成立。
先上歐拉phi函數:
memset(check,false,sizeof(check));
fai[1] = 1;
int tot = 0;
for(int i = 2 ; i <= N ; i++)
{
if(! check[i])
{
prime[tot++] = i;
fai[i] = i - 1;
}
for(int j = 0 ; j < tot ; j++)
{
if(i * prime[j] > N) break;
check[i * prime[j]] = true;
if(i % prime[j] == 0){
fai[i * prime[j]] = fai[i] * prime[j];
break;
}
else {
fai[i * prime[j]] = fai[i] * (prime[j] - 1);
}
}
}
再來個線性篩解莫比烏斯函數:
memset(check,false,sizeof(check)); mu[1] = 1; int tot = 0; for(int i = 2 ; i <= N ; i++) { if(! check[i]) { prime[tot++] = i; mu[i] = -1; } for(int j = 0 ; j < tot ; j++) { if(i * prime[j] > N) break; check[i * prime[j]] = true; if(i % prime[j] == 0){ mu[i * prime[j]] = 0; break; } else { mu[i * prime[j]] = -mu[j]; } } }