问题描述:
炫炫学了筛法之后,很想用筛法求欧拉函数。他决定求 1 1 1 到 N N N 的所有数的欧拉函
数值。
输入格式
输入的第一行包含 1 1 1 个整数 n n n 。
输出格式
输出若干行,每行包含一个整数,第 i i i 行表示 i i i 的欧拉函数值
样例输入
2
样例输出
1
1
数据规模与约定
n ≤ 500000 n \le 500000 n≤500000
前置知识
欧拉函数的定义
1 ∼ N 1∼N 1∼N 中与 N N N 互质的数的个数被称为欧拉函数,记为 ϕ ( N ) ϕ(N) ϕ(N) 。
若在算数基本定理中, N = p 1 a 1 p 2 a 2 … p m a m N=p_1^{a_1}p^{a_2}_2…p^{a_m}_m N=p1a1p2a2…pmam
则: ϕ ( N ) = N × p 1 − 1 p 1 × p 2 − 1 p 2 × . . . × p m − 1 p m ϕ(N) = N \times \frac{p_1-1}{p_1} \times \frac{p_2-1}{p_2} \times ... \times \frac{p_m-1}{p_m} ϕ(N)=N×p1p1−1×p2p2−1×...×pmpm−1
欧拉函数的证明
解题思路
利用线性筛法求出每个数的欧拉函数,质数的欧拉函数值就是 P − 1 P - 1 P−1
对于一个数 i i i ,和一个质数 p p p ,有以下两种情况:
情况1:
i m o d p = = 0 i \bmod p == 0 imodp==0 ,此时 φ ( i ∗ p ) = φ ( i ) × p \varphi(i*p) = \varphi(i) \times p φ(i∗p)=φ(i)×p,证明如下:
如果 p p p 是 i i i 的一个因子, N N N 的某一项可以变成 p k a k + 1 p_k^{a_k+1} pkak+1,即
φ ( p k a k + 1 ) = p k a k + 1 − p k a k = p k a k + 1 × ( 1 − 1 p k ) = p k × p k a k × ( 1 − 1 p k ) \varphi(p_k^{a_k+1}) = p_k^{a_k+1} - p_k^{a_k} = p_k^{a_k+1} \times (1 - \frac{1}{p_k}) = p_k \times p_k^{a_k} \times (1-\frac{1}{p_k}) φ(pkak+1)=pkak+1−pkak=pkak+1×(1−pk1)=pk×pkak×(1−pk1)
那么:
φ ( i ∗ p ) = p k × N × ( 1 − 1 p 1 ) × . . . × ( 1 − 1 p m ) = p × φ ( i ) \varphi(i*p) = p_k \times N \times (1-\frac{1}{p_1}) \times ... \times (1-\frac{1}{p_m}) = p \times \varphi(i) φ(i∗p)=pk×N×(1−p11)×...×(1−pm1)=p×φ(i)
得证。
情况二:
i m o d p ≠ 0 i \bmod p \ne 0 imodp=0,此时 φ ( i ∗ p ) = φ ( i ) × ( p − 1 ) \varphi(i*p) = \varphi(i) \times (p-1) φ(i∗p)=φ(i)×(p−1),证明如下:
其实就是 N N N 多了一个质因数 N = p 1 a 1 × . . . × p k a k × p k + 1 N = p_1^{a_1} \times ... \times p_k^{a_k} \times p_{k+1} N=p1a1×...×pkak×pk+1
所以 φ ( i ∗ p ) = φ ( i ) ∗ φ ( p ) \varphi(i*p) = \varphi(i) * \varphi(p) φ(i∗p)=φ(i)∗φ(p) ,而 φ ( p ) = p − 1 \varphi(p) = p-1 φ(p)=p−1
故: φ ( i ∗ p ) = φ ( i ) × ( p − 1 ) \varphi(i*p) = \varphi(i) \times (p-1) φ(i∗p)=φ(i)×(p−1),结论得证
代码展示
import java.io.*;
import java.util.*;
public class Main {
static final int N = 500010;
static int[] primes = new int[N];
static int[] phi = new int[N];
static boolean[] st = new boolean[N];
static int cnt;
static void get_eulers(int n) {
for (int i = 2; i <= n; i ++ ) {
if (!st[i]) {
primes[cnt++] = i;
phi[i] = i-1;
}
for (int j = 0; primes[j] <= n/i; j ++ ) {
st[i*primes[j]] = true;
if (i % primes[j] == 0) {
phi[i*primes[j]] = primes[j] * phi[i];
break;
}
phi[i*primes[j]] = phi[i] * (primes[j]-1);
}
}
}
public static void main(String[] args) throws Exception {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(System.out);
int n = Integer.parseInt(bf.readLine().split(" ")[0]);
get_eulers(n);
phi[1] = 1;
for (int i = 1; i <= n; i ++ ) pw.println(phi[i]);
pw.close();
}
}