歐拉函數,用φ(n)表示函數
歐拉函數是求小於等於n的數中與n互質的數的數目spa
辣麼,怎麼求哩?~(~o ̄▽ ̄)~ocode
能夠先在1到n-1中找到與n不互質的數,而後把他們減掉blog
好比φ(12)io
把12質因數分解,12=2*2*3,其實就是獲得了2和3兩個質因數class
而後把2的倍數和3的倍數都刪掉方法
2的倍數:2,4,6,8,10,12im
3的倍數:3,6,9,12命名
原本想直接用12 - 12/2 - 12/3img
可是6和12重複減了
因此還要把便是2的倍數又是3的倍數的數加回來 (>﹏<)
因此這樣寫12 - 12/2 - 12/3 + 12/(2*3)
這叫什麼,這叫容斥啊,容斥定理聽過吧
好比φ(30),30 = 2*3*5
因此φ(30) = 30 - 30/2 - 30/3 - 30/5 + 30/(2*3) + 30/(2*5) + 30/(3*5) - 30/(2*3*5)
可是容斥寫起來好麻煩( ̄. ̄)
有一種簡單的方法
φ(12) = 12*(1 - 1/2)*(1 - 1/3) = 12*(1 - 1/2 - 1/3 + 1/6)
φ(30) = 30*(1 - 1/2)*(1 - 1/3)*(1 - 1/5) = 30*(1 - 1/2 - 1/3 - 1/5 + 1/6 + 1/10 + 1/15 - 1/30)
你看( •̀∀•́ ),拆開後發現它幫你自動幫你容斥好
因此φ(30)的計算方法就是先找30的質因數
分別是2,3,5
而後用30* 1/2 * 2/3 * 4/5就搞定了
順便一提,phi(1) = 1
代碼以下:
1 //歐拉函數 2 int phi(int x){ 3 int ans = x; 4 for(int i = 2; i*i <= x; i++){ 5 if(x % i == 0){ 6 ans = ans / i * (i-1); 7 while(x % i == 0) x /= i; 8 } 9 } 10 if(x > 1) ans = ans / x * (x-1); 11 return ans; 12 }
(phi就是φ的讀音)
機智的代碼,機智的我(。・`ω´・)
這個的複雜度是O(√n),若是要你求n個數的歐拉函數,複雜度是O(n√n),這也太慢了
有更快的方法
跟埃篩素數差很少
1 #include<cstdio> 2 const int N = 100000 + 5; 3 int phi[N]; 4 void Euler(){ 5 phi[1] = 1; 6 for(int i = 2; i < N; i ++){ 7 if(!phi[i]){ 8 for(int j = i; j < N; j += i){ 9 if(!phi[j]) phi[j] = j; 10 phi[j] = phi[j] / i * (i-1); 11 } 12 } 13 } 14 } 15 int main(){ 16 Euler(); 17 }
(Euler就是歐拉)
另外一種,比上面更快的方法
須要用到以下性質
p爲質數
1. phi(p)=p-1 由於質數p除了1之外的因數只有p,故1至p的整數只有p與p不互質
2. 若是i mod p = 0, 那麼 phi(i * p)=phi(i) * p (我不會證實)
3.若i mod p ≠0, 那麼 phi( i * p )=phi(i) * ( p-1 ) (我不會證實)
(因此我說我會證實都是騙人的╮( ̄▽ ̄)╭)
代碼以下:
1 #include<cstdio> 2 using namespace std; 3 const int N = 1e6+10 ; 4 int phi[N], prime[N]; 5 int tot;//tot計數,表示prime[N]中有多少質數 6 void Euler(){ 7 phi[1] = 1; 8 for(int i = 2; i < N; i ++){ 9 if(!phi[i]){ 10 phi[i] = i-1; 11 prime[tot ++] = i; 12 } 13 for(int j = 0; j < tot && 1ll*i*prime[j] < N; j ++){ 14 if(i % prime[j]) phi[i * prime[j]] = phi[i] * (prime[j]-1); 15 else{ 16 phi[i * prime[j] ] = phi[i] * prime[j]; 17 break; 18 } 19 } 20 } 21 } 22 23 int main(){ 24 Euler(); 25 }
最後說下
a^b % p 不等價 (a%p)^(b%p) % p
由於
a^φ(p) ≡ 1 (mod p)
因此
a^b % p = (a%p)^(b%φ(p)) % p
(歐拉函數前提是a和p互質)
若是p是質數
直接用這個公式
機智的代碼,機智的我(。・`ω´・)
///////////////////////////////////////////////
2016年7月23號
個人天哪,我又發現了一個新公式,貌似能夠擺脫a和p互質的束縛,讓咱們來命名爲:超歐拉取模進化公式
這是歷史性的一刻,媽媽不再用爲a和p不互質而擔憂了= =