費馬小定理和歐拉定理ios
咱們如今設正整數$a,m$且$m$是素數 咱們就會有式子 $$a^{m-1}\equiv1(mod\ m)$$算法
咱們設一個徹底剩餘系$A={1,2,3,...,m-1}$ 又由於$(a,m)=1$ 咱們又獲得另外一個徹底剩餘系$B={1a,2a,3a,...,(m-1)a}$,這裏其實就是一個餘數的可乘性的運用 根據徹底剩餘系的性質咱們 $$(m-1)!\equiv(m-1)!*a^{m-1}(mod\ m)$$ 兩邊同時消去就可得 $$a^{m-1}\equiv1(mod\ m)$$函數
歐拉函數記爲$\phi$,且一般定義在正整數域上 比較直接點,歐拉函數通式是長這樣的 $$\phi(n)=n\prod^{x}{i=1}(1-\frac{1}{p_i})$$ 其中x爲n的質因數個數,而$p_i$是n的第i個質因數 其實歐拉函數更重要的意義是:$\phi(n)$表示小於等於n且與n互質的正整數的個數 由此咱們能夠的這麼一條僞通式 $$\phi(n)=\sum^{n}{i=1}[(n,i)==1]$$ 歐拉函數是積性函數,由它的意義咱們能夠用乘法原理證實,同時顯然能夠知道這不是徹底積性函數ui
例如三個正整數10,2,5,咱們能夠算到$\phi(10)=4$spa
若$(n,m)=1$,則有 $$\phi(nm)=\phi(n)*\phi(m)$$ 咱們能夠根據定義獲得若是n爲素數,則$\phi(n)=n-1$,這個東西反向也是成立的 咱們能夠根據這些性質來寫出歐拉函數的線性篩法 代碼以下:code
void getEuler(int x){ eul[1]=1; for(int i=2;i<=x;i++){ if(!eul[i]){ pri[++tot]=i; eul[i]=i-1; } for(int j=1;j<=tot and i*pri[j]<=x;j++){ if(!(i%pri[j])){ eul[i*pri[j]]=eul[i]*pri[j]; break; } eul[i*pri[j]]=eul[i]*(pri[j]-1); } } }
歐拉函數在信息學競賽中使用的仍是蠻多的,固然在解決實際數學問題中歐拉函數也是一個極其有用的東西,例如咱們在求${17}^{2017}\equiv x(mod\ 23)$時計算速度會快不少blog
給出一個正整數$n(n<=10^7)$,求 $$\sum_{i=1}^{n}\sum_{j=1}^{n}\phi({gcd(i,j)})$$get
顯然咱們暴力是過不了的咱們要考慮$O(n)$或者更高效的算法數學
咱們確定要推式子,因此直接拿那個題目的式子來推string
其中
$$sum(n)=\sum_{i=1}^{n}\phi(i)$$
這樣咱們就能夠推出原式爲
$$2*\sum^n_{d=1}{(\phi(d)*sum(\lfloor \frac{n}{d} \rfloor))}-sum(n)$$
因此咱們能夠用線性篩篩出歐拉函數而後咱們再求一次前綴和
代碼:
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int tot,n,pri[10000001]; long long eul[10000001]; inline int rd(){ register int x=0,y=1;register char c=getchar(); while(c<'0' or c>'9'){ if(c=='-')y=-1; c=getchar(); } while(c>='0' and c<='9'){ x=(x<<1)+(x<<3)+(c^48); c=getchar(); } return x*y; } void getEuler(int x){ eul[1]=1; for(int i=2;i<=x;i++){ if(!eul[i]){ pri[++tot]=i; eul[i]=i-1; } for(int j=1;j<=tot and i*pri[j]<=x;j++){ if(!(i%pri[j])){ eul[i*pri[j]]=eul[i]*pri[j]; break; } eul[i*pri[j]]=eul[i]*(pri[j]-1); } } for(int i=2;i<=x;i++)eul[i]+=eul[i-1]; } long long solve(int x){ long long ret=0;int nxt; for(int i=1;i<=x;i=nxt+1){ nxt=x/(x/i); ret+=(eul[nxt]-eul[i-1])*eul[x/i]*2-(eul[nxt]-eul[i-1]); } return ret; } int main(){ n=rd(); getEuler(10000000); while(n--){ int x=rd(); printf("%lld\n",solve(x)); } return 0; }
如今咱們來引入歐拉定理,實際上歐拉定理就是費馬小定理的推廣在m爲素數時顯然就是費馬小定理 咱們先定義兩個互質的正整數$a,m$ 咱們就會有 $$a^{\phi(m)}\equiv1(mod \ m)$$
咱們令$r=\phi(n)$ 咱們先設一個有$r$個元素的集合$P={p_1,p_2,p_3,...p_r}$,其中$p_i$是第i個與m互質的數 又由於$(a,m)=1$,且P集合中的全部元素都與m互質,因此集合$P'={ap_1,ap_2,ap_3,...ap_r}$的全部元素都與m互質,且屬於模m的r個不一樣的剩餘類$[p_1],[p_2],..[p_r]$,這裏咱們用同餘的性質很容易就能夠想到 $$a^r*\prod_{i=1}^{r}{p_i}\equiv\prod_{i=1}^{r}{p_i}(mod \ m)$$ 消去可得 $$a^r\equiv1(mod\ m)$$ 因此 $$a^{\phi(m)}\equiv1(mod\ m)$$