在数论,对正整数n,欧拉函数是 小于 n的正整数中与n互质的数的数目(φ(1)=1)。此函数以其首名研究者欧拉命名(Euler’s totient function),它又称为Euler’s totient function、φ函数、欧拉商数等。 例如φ(8)=4,因为1,3,5,7均和8互质。
其中1的欧拉函数φ(1)=1
欧拉公式的延伸:对于一个数,与其互质的数的总和是euler(n)n/2。
如φ(15)=8,有互质数 1,2,4,7,8,11,13,14,加和后结果为60,而815/2结果同为60。
通常用phi表示欧拉函数或存储欧拉函数的数组
特性 :
1.若a为质数,phi[a]=a-1;
2.若a为质数,b mod a=0,phi[a * b]=phi[b] * a【 b是 质数a 的倍数则ab的欧拉函数是b的欧拉函数的a倍 φ(a * b)=φ(b) * a】
3.若a,b互质,phi[a * b]=phi[a] * phi[b]【当a为质数时,if (b mod a)!=0 ,phi[ab]=phi[a] * phi[b]】
4.特殊性质:当n为奇数时,φ(2*n)=φ(n)
*φ(1) = 1
*φ(2) = 1
*φ(3) = 2
*φ(4) = 2
φ(5) = 4
*φ(6) = 2
φ(7) = 6
φ(8) = 4
φ(9) = 6
φ(10) = 4
φ(11) = 10
φ(12) = 4
φ(13) = 12
φ(14) = 6
φ(15) = 8
φ(16) = 8
φ(17) = 16
φ(18) = 6
φ(19) = 18
φ(20) = 8
φ(21) = 12
φ(22) = 10
φ(23) = 22
φ(24) = 8
φ(25) = 20
φ(26) = 12
φ(27) = 18
φ(28) = 12
φ(29) = 28
φ(30) = 8
φ(31) = 30
φ(32) = 16
φ(33) = 20
φ(34) = 16
φ(35) = 24
φ(36) = 12
φ(37) = 36
φ(38) = 18
φ(39) = 24
φ(40) = 16
φ(41) = 40
φ(42) = 12
φ(43) = 42
φ(44) = 20
φ(45) = 24
φ(46) = 22
φ(47) = 46
φ(48) = 16
φ(49) = 42
φ(50) = 20
可以发现只有φ(1),φ(2),φ(3),φ(4),φ(6)是质数,其余所有欧拉函数都是合数。
Euler函数表达通式:euler(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…(1-1/pn),其中p1,p2……pn为x的所有素因数,x是不为0的整数。
log(n)单个数字求解欧拉函数模板:
int phi(int n)
{
int ans=n,tmp=n;
for(int i=2; i*i<=tmp; i++) ///遍历所有质因子,其中tmp遍历范围因为去除了质因子的倍数一直在变小
{
if(tmp%i==0)
{
ans=ans/i*(i-1); ///此处是x*(1-1/p1)=x*(p1-1)/p1,为防止溢出,先计算除法
while(tmp%i==0)tmp/=i; ///去除质因子倍数
}
}
if(tmp>1)ans=ans/tmp*(tmp-1);
return ans;
}
nlog(n)打表欧拉函数:
const int MAXN=100005;
int euler[MAXN];
void Init()
{
euler[1]=1;
for(int i=2;i<MAXN;i++) euler[i]=i;
for(int i=2;i<MAXN;i++)
{
if(euler[i]==i)
{
for(int j=i;j<MAXN;j+=i)
{
euler[j]=euler[j]/i*(i-1);
}
}
}
for(int i=1;i<=50;i++)printf("φ(%d) = %d
",i,euler[i]);
}
O(n)线性筛打表欧拉函数(1s内可以打表2e7的欧拉函数):
LL euler[maxn]={0};///欧拉函数
LL prime[maxn],cnt=0;///素数
bool vis[maxn];
void Init()///线性欧拉筛
{
euler[1]=1;
memset(vis,false,sizeof vis);
for(int i=2;i<maxn;i++)
{
if(!vis[i])prime[++cnt]=i,euler[i]=i-1;///素数情况
for(int j=1;j<=cnt&&i*prime[j]<=maxn;j++)
{
vis[i*prime[j]]=1;///素数倍数非素数
if(i%prime[j])euler[i*prime[j]]=euler[i]*(prime[j]-1);
else
{
euler[i*prime[j]]=euler[i]*prime[j];
break;
}
}
// printf("φ(%d)=%lld
",i,euler[i]);
}
}