1. 程式人生 > >線性(尤拉)篩&尤拉函式

線性(尤拉)篩&尤拉函式

線性篩法

what is 線性篩??就是基於最基本的篩法的優化。
在基礎的篩法上,我們發現有的數字會被重複篩,例如6既會被2列舉到也會被3列舉到,必然有重複運算。
我們的做法就是讓每一個數的最小因數篩。
\(FOR\) \(EXAMPLE:\)
有一個數\(2 * 2 * 3 * 5\)
有另一個數 \(3 * 3 * 3* 5\)
那麼第一個數列舉到3的話,篩到的數字是\(2 * 2 * 3 * 3 * 5\)
但是在第二個數字再次列舉的時候 列舉到2時 也會列舉到\(2 * 2 * 3 * 3 * 5\)
因此,維護這個最小質因數即可。
怎麼維護??
\(i\) \(mod\) \(這個質因數\)

\(=0\) 說明是質因數,第一次列舉到就要\(break\),這樣就保證了一定會被最小素因數給篩。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n,cnt=0;
    int prime[10000]={};//用來儲存素數 
    int Vis[10000]={};//用來判斷是否是素數
    cin>>n;
    for (int i=2;i<=n;i++)
    {
        if (Vis[i]==0) prime[++cnt]=i;//如果沒有被標記過 
        for (int j=1;j<=cnt&&i*prime[j]<=n;j++)//用i去乘上每一個已經求過的素數 
        {
            Vis[i*prime[j]]=1;//標記素數 
            if (i%prime[j]==0) break;//下面再解釋 
        }
    }
    for (int i=2;i<=n;i++) 
        if (Vis[i]==0) cout<<i<<' ';
    return 0; 
} 

一、尤拉函式概念

尤拉函式,是表示1~n中與n互質的元素的個數,記為\(φ(n)\)

二、性質

  • 如果n為某一素數p,顯然\(φ(p)\)為p-1
  • 如果n為某一素數的冪次,那麼: \[\phi(p^a)=(p-1)*p^ {a-1}\]
    我們可以來推導次函式的求法
    我們先將n分解質因數得:
    \[n=a1^{b1}*a2^{b2}*a3^{b3}*……*ak^{bk}\]

因為φ(n)求的是與n互質的數的個數,所以其中不能有n的因數,即不能出現a1,a2,a3……ak的倍數。
那麼我們來轉換思路,n個數之中存在多少個a1的倍數,多少個a2的倍數……多少個ak的倍數呢?
顯然有n/a1個a1的倍數,n/a2個a2的倍數……有n/ak個ak的倍數。

所以\(φ(n)=n-\frac{1}{a1} -\frac{1}{a2}-\frac{1}{a3}-……-\frac{1}{ak}\)
將n提取出來得到:
\[φ(n)=n*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})\]

於是尤拉函式的公式就這麼推匯出來了

還有如下性質:

  • 如果i mod p=0,那麼\(φ(i*p)=p*φ(i)\)
    證明:
    對於公式\[φ(1)=n*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})\]
    得到
    \[φ(n)=n*p*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})\]
    因為p已經是i的因數,後半部分不需要新增
    因此得證。
  • 函式的積性,\(φ(i*j)=φ(i)*φ(j)\)

  • 如果i mod p≠0,那麼\(φ(i*p)=φ(i)*(p-1)\)
    根據
    \[φ(n)=n*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})\]
    得到
    \[φ(n)=n*p*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})*(1-\frac{1}{p})\]
    因為p不是i的因數,因此最後要加上\((1-\frac{n}{ak})\)部分。
    證明完成。

三、求法

下面給兩種求法。

\(1\).公式法

根據公式\(φ(n)=n*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})*(1-\frac{1}{p})\)

inline LL eular(LL x)
{
    LL sum=x,y=x;
    for (LL i=2;i*i<=y;++i)
    {
        if (x%i!=0) continue;
        sum=sum/i*(i-1); 
        while (x%i==0) x/=i;
    }
    if (x>=2) sum=sum/x*(x-1);
    return sum;
}
//公式求x尤拉函式 

\(2\).線性篩求尤拉函式

根據三條性質推導即可。
線性篩中每一個數字最多隻會被篩一次,因此正好可以對每一個數字求尤拉函式。
線性篩正好是由小的數字篩到大的數字 or 正好是指數
前者用後兩條性質 後者用第一條性質即可。
三條性質如下:

  • 如果n為某一素數的冪次,那麼: \(\phi(p^a)=(p-1)*p^ {a-1}\)
  • 如果i mod p=0,那麼\(φ(i*p)=p*φ(i)\)
  • 如果i mod p≠0,那麼\(φ(i*p)=φ(i)*(p-1)\)
inline void findphi(void)
{
    phi[1]=1,prm[1]=0;
    for (LL i=2;i<=n;++i)
    {
        if (!v[i]) { prm[++cnt]=i, phi[i]=i-1; }
        for (LL j=1;j<=cnt && i*prm[j]<=n;++j)
        {
            v[i*prm[j]]=1;
            if (i%prm[j]==0) { phi[i*prm[j]]=phi[i]*prm[j]; break; }
            if (i%prm[j]!=0) phi[i*prm[j]]=phi[i]*(prm[j]-1);   
        }   
    }
    return; 
} 

後記

部分參考hkh大佬的部落格。
在此表示感謝!
如有紕漏請讀者指正!
<\font>