可通过容斥原理证明上述
ϕ
(
N
)
\phi{(N)}
ϕ(N)
int phi(int x)
{
int res = x;
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0)
{
res = res / i * (i - 1);
while (x % i == 0) x /= i;
}
if (x > 1) res = res / x * (x - 1);
return res;
}
tip: 当 m,n 互质时, ϕ ( m ∗ n ) \phi(m * n) ϕ(m∗n) = ϕ ( m ) \phi(m) ϕ(m) * ϕ ( n ) \phi(n) ϕ(n)
质数 i 的欧拉函数 phi[i] = i - 1 :1 ~ i - 1 均与 i 互质;
i * primes[j] (合数) 时,
i % primes[j] == 0
时,primes[j] 是 i 的最小质因子,也是primes[j] 的最小质因子,因此
1
−
1
p
r
i
m
e
s
[
j
]
1-\frac{1}{primes[j]}
1−primes[j]1 在 phi[i] 中已经计算过了(
ϕ
(
N
)
\phi(N)
ϕ(N)中只与质因子种类有关而与每个质因子的数目无关)。故只需要将基数 N 进行修订,即为原本的 primes[j] 倍。最终结果为 phi[i] * primes[j]
i % primes[j] != 0
时,primes[j] 不是 i 的质因子,只是 i * primes[j] 的最小质因子,因此不仅要将基数 N 修订为原来的 primes[j] 倍,还需要补上
1
−
1
p
r
i
m
e
s
[
j
]
1-\frac{1}{primes[j]}
1−primes[j]1 这一项。最终结果为 ph[i] * (primes[j] - 1)
int primes[N], cnt; // primes[]存储所有素数
int euler[N]; // 存储每个数的欧拉函数
bool st[N]; // st[x]存储x是否被筛掉
void get_eulers(int n)
{
euler[1] = 1;
for (int i = 2; i <= n; i ++ )
{
if (!st[i])
{
primes[cnt ++ ] = i;
euler[i] = i - 1;
}
for (int j = 0; primes[j] <= n / i; j ++ )
{
int t = primes[j] * i;
st[t] = true;
if (i % primes[j] == 0)
{
euler[t] = euler[i] * primes[j];
break;
}
euler[t] = euler[i] * (primes[j] - 1);
}
}
}