欧拉函数是一个好东西.
欧拉函数的符号为φ,其中φ(n)表示1~n中与n互质的数的个数.
那么φ(n)的求法如下:
φ(n)=N*(p1-1)/p1*(p2-1)/p2*...*(pm-1)/pm.
其中p1,p2,...,pn什么的是唯一分解定理中n=p1^c1*p2^c2*p3^c3...*pm^cm.
若p是N的因子,就会筛掉n/p个数,同时q也会筛掉n/q个数,但它们中间的那部分n/(p*q)得加回来.
也就是我们可以推导出:N-n/p-n/q+n/(p*q)=N*(1-1/p)*(1-1/q).
那么代码实现如下:
int phi(int n){ int ans=n; for (int i=1;i<=sqrt(n);i++) if (n%i==0){ ans=ans/i*(i-1); while (n%i==0) n/=i; } if (n>1) ans=ans/n*(n-1); return ans; }
那么这是一种O(sqrt(n))的算法.
当然它还可以在线性的时间里推出phi(1~n).
这就要利用到线性筛了.
线性筛blog地址:https://blog.csdn.net/hzk_cpp/article/details/80418319.
首先我们介绍几个欧拉函数的性质才能用线性筛求:
1.若n为素数,则φ(n)=n-1.
2.φ(a*b)=φ(a)*φ(b).
3.当p为素数时,φ(p^k)=(p-1)*p^(k-1).
证明:
首先比令n=p^k,那么比n小的正整数有p^k-1个.
容易得出其中与n不互素的数共有p^(k-1)-1个.
所以φ(p^k)=(p^k-1)-(p^(k-1)-1)=p^k-p^(k-1)=(p-1)*p^(k-1).
4.当p为素数时,若i%p=0,则φ(i*p)=p*φ(i).
5.当p为素数时,若i%p≠0,则φ(i*p)=(p-1)*φ(i).
那么用线性筛的思想,代码就很好写了:
const int N=10000000; int pr[N+1],top=0,phi[N+1]; bool b[N+1]; void prime(int n){ top=0; memset(b,1,sizeof(b)); b[0]=0;b[1]=0; phi[0]=0;phi[1]=0; for (int i=2;i<=n;i++){ if (b[i]) pr[++top]=i,phi[i]=i-1; for (int j=1;j<=top&&pr[j]*i<=n;j++){ b[pr[j]*i]=0; if (i%pr[j]==0) { phi[i*pr[j]]=phi[i]*pr[j]; break; }else phi[i*pr[j]]=phi[i]*(pr[j]-1); } } }
再来一个定理叫做欧拉定理.
若a,p互质,则a^φ(p)≡1(mod p).
那么证明可以这样:
我们可以证明,集合{a1,a2,a3,...,aφ(p)}与{a*a1,a*a2,...,a*aφ(p)}在mod p意义下是同一个集合.
那么也就是说a^φ(p)*a1*a2*...*aφ(p)≡a1*a2*...*aφ(p)(mod p).
即a^φ(p)≡1(mod p).
证明过程很简洁吧.
其实是我太懒了,两个集合为什么相同未证.
那么这个定理还有一个推论:若a,n互质,则对于任意正整数b有a^b≡a^(b mod φ(n)) (mod n).
证明就是:设b=q*φ(n)+r,那么a^b≡a^(q*φ(n)+r)≡(a^φ(n))^q*a^r≡1*a^r≡a^(b mod φ(n)) (mod n).
接下来还有一个费马小定理:若p为素数,则a^p≡a (mod p).
用欧拉定理就可以证明.
至于这些东西有什么用,我也很想知道.