1. 程式人生 > >[數論]尤拉函式&素數篩

[數論]尤拉函式&素數篩

一、尤拉函式

尤拉函式是小於x的整數中與x互質的數的個數,一般用φ(x)表示。

通式:   其中p1, p2……pn為x的所有質因數,x是不為0的整數。
  • 比如x=12,拆成質因數為12=2*2*3,
  • 12以內有1/2的數是2的倍數,那麼有1-1/2的數不是2的倍數(1,3,5,7,9,11),
  • 這6個數裡又有1/3的數是3的倍數,
  • 只剩下(1 - 1/2 - 1/3)的數既不是2的倍數,也不是3的倍數(1,5,7,11)。
  • 這樣剩下的12*(1 - 1/2 - 1/3)=4,即4個數與12互質,所以φ(12)=4。

證明:對於正整數x,

  • 如果x=1,則 φ(1) = 1。
    • 1與任何數(包括自身)都構成互質關係。
  • 如果x是質數,則 φ(x)=x-1 。
    • 質數與小於它的每一個數,都構成互質關係。比如5與1、2、3、4都構成互質關係。
  • 如果n只有一個質因數p,即x = p^k(p為質數,k>=1),則φ(pk)=pk(1-1/p)=pk-pk-1 。
    • 從1~x中,p的倍數共有x/p個,共佔了1/p,則減去這些數後,還剩下x*(1-1/p)個。
    • 可以看出,上一種情況是 k=1 時的特例。
  • 如果n可以分解成兩個互質的整數之積,即n = p1 * p2,φ(x) = φ(p* p2) = φ(p1) * φ(p2)。
    • 積性函式:若當m與n互質時,f(m∗n)=f(m)∗f(n) f(m*n)=f(m)*f(n)f(m∗n)=f(m)∗f(n),那麼f是積性函式。
    • 尤拉函式是積性函式(證明略)。
  • 任意一個大於1的正整數,都可以寫成一系列質數的積。
  • 可以得到,φ(x) = φ(p1)*φ(p2)*...*φ(pn) = x(1-1/p1)*(1-1/p2)*...*(1-1/pn).

一些(目前不需要的)性質:

  • 當n>2時,φ(n)是偶數。
  • 小於n的數中,與n互質的數的總和為:φ(n) * n / 2 (n>1)。
  • n的因數(包括1和它自己)的尤拉函式之和等於n。
  • 若n為奇數時,φ(2n)=φ(n)。
  • 對於任何兩個互質的正整數a,n(n>2)有:a^φ(n)=1 mod n (恆等於)此公式即 尤拉定理。
  • 當n=p 且 a與素數p互質(即:gcd(a,p)=1)則上式有: a^(p-1)=1 mod n (恆等於)此公式即 費馬小定理。


求尤拉函式:

1.埃拉託斯特尼篩

求1~n所有數的尤拉函式:每次找到一個質數,就把它的倍數更新掉。複雜度大概是O(nlognlogn)。

void euler(int n){
    for (int i=1;i<=n;i++) phi[i]=i;
    for (int i=2;i<=n;i++)
        if (phi[i]==i)for (int j=i;j<=n;j+=i)
                phi[j]=phi[j]/i*(i-1);

2.尤拉篩

每次找到一個最小的因數(一定為質因數),求出x*(1 - 1/p)。複雜度為O(n)。

int euler(int n){
     int res=n,a=n;    
     for(int i=2;i*i<=a;i++){
         if(a%i==0){    
             res=res/i*(i-1);
             while(a%i==0) a/=i;    
         }    
   }
if(a>1) res=res/a*(a-1); return res; }

對於x = p1^k * p2^m...,只需要求一次(1-p1)(1-p2)...就可以了,

為了保證每個質因數只被使用一次,通過以上的while迴圈把x中的p1除盡。

 

二、素數篩法

好睏(我覺得這個寫的挺好)

 

參考文章:

https://blog.csdn.net/liuzibujian/article/details/81086324

https://blog.csdn.net/paxhujing/article/details/51353672