小於n且與n互素的整數個數(尤拉函式)的計算
阿新 • • 發佈:2019-01-25
即計算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; }