線性篩是一個比較有用的東東,
所以得好好記住辣。。。
對於普通的篩素數方法,
就是枚舉一個i,然後和所有已知素數prime[j]相乘,
i*prime[j]就不是素數了,去掉即可。
如果這樣的話是基本O(nlogn)的,
線性篩就是在這個篩法的基礎上加入了一個優化,
每次讓一個數只被它的最小質因子篩一次,
也就是如果i%prime[j]=0,直接break即可。
這樣的話就能優化到O(n)了,代碼如下:
//notprime[i]=1表示i不是質數,不然表示i爲質數
//prime[i]記錄第i個素數,pcnt記錄素數的個數
//MAX爲最大值
void Get_Prime(){
notprime[1]=1,pcnt=0;
for (int i=2;i<MAX;i++){
if (!notprime[i]) prime[++pcnt]=i;
for (int j=1;j<=pcnt;j++){
if (prime[j]*i>=MAX) break;
notprime[prime[j]*i]=1;
if (!(i%prime[j])) break; //線性篩的重要優化
}
}
}
對於歐拉函數,根據它的定義式:
那麼對於一個n,可以在O(logn)的時間內計算phi(n),
如果要計算1~n的每個數的phi,就需要O(nlogn)的時間了;
然而其實求1~n每個數的歐拉函數是可以做到O(n)的,
就是在線性篩的基礎上增加幾句,,
這都基於歐拉函數的幾個性質:
1.
2.
3.
積性函數的一個東東啦。。
於是在線性篩素數的過程中我們也可以線性篩出歐拉函數了。
如果要歐拉函數求和,只要對phi做個前綴和就好辣!
//這裏n是最大值
void get_eula_prime(){
notprime[1]=1,pcnt=0;
phi[1]=1;
for (int i=2;i<=n;i++){
if (!notprime[i]) phi[i]=i-1,prime[++pcnt]=i;
for (int j=1;j<=pcnt;j++){
if (i*prime[j]>n) break;
notprime[i*prime[j]]=1;
if (i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
} else phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
線性篩素數是一直要用的,
而線性篩歐拉函數要看情況,有時候可能直接O(logn)會更優,
要適當選擇。