在數論中,對正整數N,歐拉函數是小於或等於N的數中與N互質的數的數目。
N的歐拉函數值記為 phi(n)
例如 phi(8)=4 (4個與8互質的數分別為 1 3 5 7)
通式: ,其中p1, p2……pn為x的所有質因數,x是不為0的整數。φ(1)=1(唯一和1 互質 的數(小於等於1)就是1本身)。 (注意:每種質因數只一個。比如12=2*2*3那麼φ(12)=12*(1-1/2)*(1-1/3)=4
故求phi(x)模板為:
int phi(int x){//註:ans即為phi(x)的值 int ans=x;//先令phi(x)=x,公式中的前部分 for(int i=2;i*i<=x;i++){//枚舉每個數(注意,phi要求的因子是質數,而這裡枚舉的是所有數。至於為什麼要這麼枚舉,請看代碼下邊的解釋) if(x%i==0){//如果這個數是因子 ans-=ans/i;//套公式x*(1-1/pi)=x-x/pi即這裡的ans-=ans/i; while(x%i==0) x/=i;//篩去phi(x)中x的所有i因子 } } if(x>1)//篩後有剩餘的數,說明這個數也是一個質因子 ans-=ans/x;//同理套公式 return ans;//答案}在這裡解釋一下為什麼要枚舉每個數:
很簡單本模板中“從小到大枚舉每個數“和”從小到大枚舉每個質數“是一樣的
因為所有合數都可以被分解為質數相乘的形式。
注意到while(x%i==0) x/=i;
x每次都會篩去質因子,
比如在phi(8)
4這個合數因子,已經在篩2這個質因子時篩去了
因為4=2*2,而篩到2時,所有的因子2已被篩去。
此時,phi(X)中x的值已經改變,不再是8。
篩到4的時候x%4不會==0。
那麼如果我們需要打出phi(MAXN)的表該怎麼做呢。不用把上面的模板從1迴圈到MAXN。我們有更機智的做法。
模板:
int p[MAXN];void phi(){ for(int i=1;i<MAXN;i++) p[i]=i; for(int i=2;i<MAXN;i++){ if(p[i]==i){ for(int j=i;j<MAXN;j+=i) p[j]-=p[j]/i; } }} 如果你會素數篩的話,恭喜你,這就是個素數篩。
只不過在素數篩中我們篩出的每個素數是用來存起來的
而在這裡我們篩出的每個素數
作為一個素因子
“主動地”去找包含這個素因子的數
然後套公式。