1. 程式人生 > >尤拉篩法 && 尤拉函式

尤拉篩法 && 尤拉函式

尤拉篩

對於O(nlognlogn)的埃拉特斯特尼篩法:

>for(int i=2;i<n;i++)
    {
        if(!vis[i])
        {
           prime[cnt++]=i;//儲存素數 
           for(int j=i*i;j<n;j+=i)//i*i開始進行了稍微的優化
           vis[j]=1;//因為 i 為素數 所以 i 的倍數  都是 合數 
        }
    }

可以發現有被重複篩到的數比如30 =2 * 15 =3 * 10 = 5* 6

尤拉篩就巧妙地讓每個數都只被最小的質因子篩掉從而使複雜度變為O(n)

    for(int i=2;i<=maxn;i++)
    {
        if(!notprime[i])
        {
            prime[++cnt]=i;//統計質數
        }
        for(int j=1;j<=cnt&&prime[j]*i<=maxn;j++)
        {
            notprime[i*prime[j]]=1;
            if(i%prime[j]==0)//這裡是精髓
                break;
        }
    }

通過

if(i%prime[j]==0)

這一句就實現了保證每個數只其最小質因子被篩一次
為啥?
對於一個數 a 假設它可以整除prime[ j ]
即 a= prime[ j ] * x
那麼 a* prime[ j +1 ] = prime[ j ]* x * prime[ j+1 ]
所以 j 再往後就 沒有必要篩了
因為a*prime[ j+1 ] 肯定會在 i= x * prime[ j+1 ]的時候被prime[ j ]篩掉

比如對於 i = 6 時
可以知道 6 = 2 * 3
那麼 j=1 即 prime[ j ] = 2 時 2 * 6 = 12 被篩掉並退出迴圈
此時3 * 6 = 18並不會被篩掉因為18 = 3 * 2 * 3
所以後來當i= 9時 才會篩掉2 * 9 =18

尤拉函式

定義:在數論中,對正整數n,尤拉函式是小於或等於n的數中與n**互質**的數的數目。
分幾種情況

  1. 當n為質數時 phi( n ) = n-1因為質數的因數只有1和本身

  2. 若n為質數p的k次方 那麼phin=pkpk1=pk(11p)
    因為只有當一個數不包含質數p才可能與n互質,而包含質數p的數一共有1×p,2×p,3×p,...pp1×ppk1

  3. 若n為兩個質數p1 p2 的乘積: 如果a與p1互質(a < p1),b與p2互質(b < p2),c與p1p2互質(c < p1p2),則c與數對 (a,b) 是一一對應關係。由於a的值有φ(p1)種可能,b的值有φ(p2)種可能,則數對 (a,b) 有φ(p1)φ(p2)種可能,而c的值有φ(p1p2)種可能,所以φ(p1p2)就等於φ(p1)φ(p2)。有

    phi(n)=pk1×pk2×(11p1)(11p2)=n×(11p1)(11p2)
    (尤拉函式的積性性質)
    ————若ab互質,則phi(a* b)=phi(a)*phi(b)

    因為任意一個大於1的正整數都可以寫成一系列質數的乘積
    根據上面的性質可以推得

    n=p1×p2×...×pn (p均為質數)
    那麼phi(n)=p1×p2×...×pn×(11p1)(11p2)...(11pn)=n×(11p1)(11p2)...(11pn)

所以利用尤拉函式的性質:

可以得到:

設p為質數
如果p為x的因數
那麼phi(p×x)=p×x×(11p1)×...×(11pn)=phi(p)×x
如果p不是x的因數 即 p x互質
那麼phi(p×x)=phi(p)×phi(x)=phi(x)×(p1)

那麼我們可以在篩質數的同時O(n)求出1~n的Eular函式值

具體實現如下:

for(int i=2;i<=maxn;i++)
    {
        if(!isprime[i])
        {
            prime[++cnt]=i;
            phi[i]=i-1;//質數直接能求出
        }
        for(int j=1;j<=cnt&&prime[j]*i<=maxn;j++)
        {
            isprime[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];//px不互質
                break;
            }
            else phi[i*prime[j]]=phi[i]*(prime[j]-1);//px互質
        }
    }

收工啦~