基本定理:
首先看一下核心代碼:
核心代碼
原理解析:
當初我看不懂這段代碼,主要有這么幾個問題:
1.定理里面不是一開始寫了一個n*xxx么?為什么代碼里沒有*n?
2.ans不是*(prime[i]-1)么?為什么到了第二個while循環變成*prime[i]了?
3.定理里面不是要/pi么?為什么代碼里沒有/pi?????????????
公式化簡
首先我們來分析一下整個程序的原理,如果把程序的原理搞明白了,這三個問題也就自然而然的解決了
這個程序的原理是基於唯一分解定理:
那么我們可以把n拆開,再帶回到歐拉函數公式中,然后再約分一下:
LaTex代碼:
1 ans=p_1^a^1*p_2^a^2*.......*p_i^a^i*\frac{p_1-1}{p_1}*\frac{p_2-1}{p_2}*....*\frac{p_i-1}{p_i} 2 \newline 3 =p_1^a^1*\frac{p_1-1}{p_1}*.......*p_2^a^2*\frac{p_2-1}{p_2}*....p_i^a^i*\frac{p_i-1}{p_i} 4 \newline 5 =p_1^a^{1-1}*({p_1-1})*.......*p_2^a^{2-1}*({p_2-1})*....p_i^a^{i-1}*({p_i-1})
解答問題
首先這里的代碼實現還有一個小技巧:
我們在while之前把x/prime[i],這就相當於讓ans少*一個prime[i],這樣就可以解決求指數ai-1的問題了
現在再回去看一下剛開始的三個問題,仔細想一想
提示:
下面有答案,
但請認真思考以后再看,
答案在下面:
1.定理里面不是一開始寫了一個n*xxx么?為什么代碼里沒有*n?
因為n被唯一分解了,while循環里面的內容就是用來*n的
2.ans不是*(prime[i]-1)么?為什么到了第二個while循環變成*prime[i]了?
*prime是為了讓答案最終*n
3.定理里面不是要/pi么?為什么代碼里沒有/pi?????????????
被化簡了,不明白的可以看上面的化簡過程
完整代碼
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 const int MAXN=1000001; 7 int prime[MAXN]; 8 int mu[MAXN]= {0,1}; 9 int n; 10 int tot=0; 11 int vis[MAXN]= {1,1}; 12 void read(int &n) { 13 char c='+'; 14 int x=0; 15 bool flag=0; 16 while(c<'0'||c>'9') { 17 c=getchar(); 18 if(c=='-')flag=1; 19 } 20 while(c>='0'&&c<='9') { 21 x=x*10+c-48; 22 c=getchar(); 23 } 24 flag==1?n=-x:n=x; 25 } 26 void ou() { 27 for(int i=2; i<=n; i++) { 28 if(!vis[i]) 29 prime[++tot]=i,mu[i]=-1; 30 for(int j=1; j<=tot&&j*prime[i]<=n; j++) { 31 vis[i*prime[j]]=1; 32 if((i%prime[j])==0) { 33 mu[i*prime[j]]=0; 34 break; 35 } 36 mu[i*prime[j]]=-mu[i]; 37 } 38 } 39 } 40 int getphi(int x) { 41 int ans=1; 42 for(int i=1; i<=tot&&prime[i]*prime[i]<=x; i++) 43 { 44 if(x%prime[i]==0) 45 { 46 ans*=(prime[i]-1); 47 x=x/prime[i]; 48 while(x%prime[i]==0) 49 { 50 ans*=prime[i]; 51 x/=prime[i]; 52 } 53 } 54 55 } 56 if(x>1) 57 ans*=x-1; 58 return ans; 59 } 60 int main() { 61 n=1001; 62 ou(); 63 int c; 64 printf("please input the num\n"); 65 while(cin>>c) 66 printf("the num`s phi is %d\n",getphi(c)); 67 return 0; 68 69 }
里面還亂入了線性求莫比烏斯函數的方法,,
懶得刪了,,,
結尾啰嗦幾句
求單值歐拉函數就講到這里,
其實對於這份代碼還有一種很玄學的理解方法,
但是我的這種方法比較簡單易懂,
而且這兩種理解方法從本質上來說是一樣的
這里不在贅述
最后再說一下,這里只介紹了求單值歐拉函數的方法,
實際上歐拉函數還有線性篩法(因為歐拉函數是積性函數)
有空再介紹吧
另外,因為本人是第一次接觸歐拉函數,所以本文肯定有成堆的bug,如果您找出了bug,可以在評論區留言或者通過其他方式聯系本人,
謝謝!