对任意整数n来说,把{1,2,3,4,5......n-1}中与n互质的数的个数称为欧拉函数φ(n),如φ(3)=2,φ(5)=4,很明显的,由此我们可知,当n为质数(n与比他小的数都互质)时,φ(n)=n-1,当n为合数时,φ(n)<n-1。
欧拉函数的值可以由公式 直接推出,p1到pn是x的质因数,利用容斥的证明:
我们可以枚举n的素因子来模拟这个过程,因为任意一个合数都有一个不超过√n的素因子,所以枚举的复杂度是O(√n)
我们把n乘到第一个括号中,那么就是n-n/p1,设res=n-n/p1,再把res乘到第二个括号里面就是res-res/p2,我们只要重复这个过程就能得到欧拉函数的值了
int phi(int n)
{
int res=n;
for(int i=2;i*i<=n;i++)//枚举质因子
{
if(n%i==0)
{
res=res-res/i;//模拟上述过程
while(n%i==0)
n/=i;
}
}
if(n>1)//处理最后一个质因子,若有的话
res=res-res/n;
return res;
}
欧拉函数的两条性质:
1.由欧拉函数为积性函数,若n与m互质那么
2.若n为奇数
证明一:若有n与m互质,则m,n无公因数,所以φ(m)φ(n)=m(1-1/p1)(1-1/p2)(1-1/p3)…(1-1/pn)·n(1-1/p1')(1-1/p2')(1-1/p3')…(1-1/pn'),其中p1,p2,p3...pn为m的质因数,p1',p2',p3'...pn'为n的质因数,而m,n无公因数,所以p1,p2,p3...pn,p1',p2',p3'...pn'互不相同,所以p1,p2,p3...pn,p1',p2',p3'...pn'均为mn的质因数且为mn质因数的全集,所以φ(mn)=mn(1-1/p1)(1-1/p2)(1-1/p3)…(1-1/pn)(1-1/p1')(1-1/p2')(1-1/p3')…(1-1/pn'),所以φ(mn)=φ(m)φ(n)
证明二:若n为奇数,则2不为其质因数,那么φ(n)=n(1-1/p1)(1-1/p2)(1-1/p3)…(1-1/pn),对于2n来说质因数只是多了一个2,那么φ(2n)=2n(1-1/2)(1-1/p1)(1-1/p2)(1-1/p3)…(1-1/pn),2n代入第一个括号后有2n-n=n与φ(n)相同,证毕
那么我们遇到要多次求得一个数的欧拉函数值时,为了比较方便我们应该来打个表,那么我们怎么来打表呢,那就是利用上面的两条欧拉函数的性质,我们先让φ(i)=i,即欧拉函数都等于自己,然后再利用第二条性质偶数的欧拉函数值为其二分之一奇数的欧拉函数值,我们枚举奇数因为除二之外的质数都是奇数,当遇到奇数的欧拉函数值为其自己时说明是一个质数,接着我们要把这个数的欧拉函数值改变,同样的也要改变能被这个质数整除的数的欧拉函数值
#define maxn 66666
int euler[maxn+1];
void phi()
{
for(int i=1;i<=maxn;i++)//预处理i的欧拉函数值为i,为了遇到是质数的情况
euler[i]=i;
for(int i=2;i<=maxn;i+=2)//利用性质二将偶数的欧拉函数值变为奇数的
euler[i]/=2;
for(int i=3;i<=maxn;i+=2)
{
if(euler[i]==i) //当是质数时,来处理其他数的质因数,利用公式来处理
{
for(int j=i;j<=maxn;j+=i)
{
euler[j]=euler[j]-euler[j]/i;//为本身的质数可在这减一
}
}
}
return ;
}