欧拉函数的公式为:
ϕ
(
x
)
=
x
∏
i
−
1
n
(
1
−
1
p
i
)
\phi(x)=x\prod_{i-1}^n(1-\frac{1}{p_i})
ϕ(x)=xi−1∏n(1−pi1)
线性复杂度的原因是因为它保证了每个合数只会被筛到一次。
每个合数都可以表示成一个数与另一个质数的乘积。
为什么 if(i%p[j]==0)
时 break
?
假设
i
=
p
1
k
1
×
p
2
k
2
.
.
.
×
p
n
k
n
i=p_1^{k_1}\times p_2^{k_2}... \times p_n^{k_n}
i=p1k1×p2k2...×pnkn,其中
p
p
p 是素数因子且递增的。那么在代码中,筛到
p
1
p_1
p1 时就会 break
了,而不需要往后筛,因为往后筛的数可以通过更大的
i
i
i 来筛得。
假设我们往后筛,则筛出的数为
i
×
p
2
i \times p_2
i×p2,这可以通过
i
×
p
2
p
1
\frac{i \times p_2}{p_1}
p1i×p2 这个比
i
i
i 大的数来乘
p
1
p_1
p1 筛得,对更后面的数也类似。
void init()
{
int c=0;
phi[1]=1;
for(int i=2;i<N;++i)
{
if(!nop[i])
{
p[c++]=i;
phi[i]=i-1;
}
for(int j=0;j<c&&i*p[j]<N;++j)
{
nop[i*p[j]]=true;
if(i%p[j]==0)
{
phi[i*p[j]]=phi[i]*p[j];
break;
}
else phi[i*p[j]]=phi[i]*(p[j]-1);
}
}
}