1. 程式人生 > >小於n且與n互素的整數個數(尤拉函式)的計算

小於n且與n互素的整數個數(尤拉函式)的計算

即計算1~n中與n互素的整數個數

互素就是無法被n整除的數("與p互素"和"不是p的倍數"是等價的)

所以第一種顯而易見的方法就是暴力列舉法,但效率太低。

第二種方法用唯一分解定律再運用容斥原理:

分解定律:分為n=p1^a1*p2^a2......pk^ak;

容斥原理:在計數時,要保證無一重複,無一遺漏。為了使重疊部分不被重複計算,在不考慮重疊的情況下,把包含於某內容中的所有物件的數目先計算出來,然後再把計數時重複計算的數目排斥出去,使得計算的結果既無遺漏又無重複,這種計數的方法稱為容斥原理。

也即是A∪B∪C=A+B+C-A∩B-B∩C-C∩A+A∩B∩C

於是可以總結出規律:偶數項相加,奇數項相減

所以1~n中與n互素的整數個數= n-p1,p2,p3,p4.....pk的倍數(即-n/p1-n/p2-n/p3...)

                                                      + p1*p2,p1*p3....的倍數(即n/(p1*p2)+n/(p1*p3)....)

                                                       - p1*p2*p3,p1*p2*p4.......的倍數(即-n/(p1*p2*p3)-n/(p1*p2*p4).....)以此類推

這個數算出來就是尤拉函式,即 φ(N)=N*(1-1/P1)*(1-1/P2)*...*(1-1/Pn)

;

嘗試展開這個公式就會發現與上面那個推導的式子一樣,假如從括號中任選一個值出來乘就會發現偶數項為正,奇數項為負,且項與上式一樣;

對於求φ(N)只需迴圈計算得出值就好了

對於求1~n中所有尤拉函式的值不需要依次計算

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
void phi_table(int n,int *phi)
{
	for(int i=1;i<=n;i++) phi[i]=0;
	phi[0]=1;
	for(int i=2;i<=n;i++)
	if(!phi[i])               //每一項i都是素數
	for(int j=i;j<=n;j+=i)     //i的倍數肯定都包含這個素因數 
	{
		if(!phi[j]) phi[j]=j;  //未計算的初始化為j,為了計算式子n*(1-1/p)中的n;
		phi[j]=phi[j]/i*(i-1);
	}
}
int main()
{
	int phi[100+5];
	phi_table(100,phi);
	for(int i=1;i<=100;i++)
	cout<<phi[i]<<' '<<i<<endl;
	return 0;
}