尤拉篩(線性篩)& 尤拉函式
阿新 • • 發佈:2019-02-13
今天又複習了一下尤拉篩法,在這做個筆記。
尤拉篩(線性篩)
一般情況下,有一種篩法叫埃什麼什麼的。是
原理
這可能原理有點妙啊。
- 設
pr[i] 為i最小質因子,然後從2開始計算 - 如果
pr[i] 沒有在前面得到,就說明i是質數,所以pr[i]=i,prime[++len]=i 。 - 對於i,列舉每一個不超過
pr[i] 的質數prime[j] ,所以pr[i∗prime[j]]=prime[j]
這樣可以發現,每一個數只會被它最小的質因子篩去,所以保證了演算法為
我們見一下程式碼:
程式碼
void find_prime(int n)
{
memset(isprime,0,sizeof(isprime));
sp = 0;
for(int i = 2;i <= n;i++)
{
if(!isprime[i])
{
prime[++sp] = i;
isprime[i] = i;
}
for(int j = 1;j <= sp && i * prime[j] <= n;j++) {
isprime[i*prime[j]] = prime[j];
if (prime[j] >= isprime[i]) break;//用isprime[i]來表示i的最小質因子,可能用mod比較慢
}
}
}
在break那一行,有的人會用
if(i % prime[j]==0) break;
不過也可以通過isprime[i]儲存i最小的質因子來與prime[j]做比較。
但不管怎麼寫,我人認為最重要的就是含break的那個語句
尤拉函式
不過,僅僅篩素數就顯得線性篩不是那麼必要。
線性篩最科學的戰場——求積性函式
作為蒟蒻,我以尤拉函式來舉例:
程式碼
先粗淺地看一下程式碼
void find_prime(int n)
{
memset(isprime,0,sizeof(isprime));
sp = 0;
for(int i = 2;i <= n;i++)
{
if(!isprime[i])
{
prime[++sp] = i;
isprime[i] = i;
phi[i] = i-1;//①
}
for(int j = 1;j <= sp && i * prime[j] <= n;j++) {
isprime[i*prime[j]] = prime[j];
if(prime[j] >= isprime[i]) {
phi[i*prime[j]] = phi[i]*prime[j];//②
break;
}
phi[i*prime[j]] = phi[i]*(prime[j]-1);//③
}
}
}
原理
- 每個數字只會被篩到一次
- 當正整數p為素數時,
phi[p]=p−1 - 尤拉函式既然是積性函式,就說明當a與b互質時,滿足
phi(a∗b)=phi(a)∗phi(b) - 當p為素數時,
phi(pk)=(p−1)∗pk−1 - 我們保證了每次的
prime[j] 小於等於i的最小質因子,所以當prime[j]<isprime[i] 時,phi[i∗prime[i]]=phi[i]∗phi[j]=phi[i]∗(j−1) ,而在i%prime[j]==0時,直接乘上prim[j] 。
上述的五點:1表明每個數值被算一次。2解釋了①。3、4、5解釋了②和③。