オイラーの φ 関数

$N$ を割り切る素数を $p_1, \ldots, p_k$ とすると $\varphi(N) = N (1 - 1/p_1) \cdots (1 - 1/p_k)$ であることを使います。

$a$ と $N$ が互いに素なとき $a^{\varphi(N)} \equiv 1 \pmod{N}$ が成り立ちます(オイラーの定理)。また、分母が $N$ の既約分数で $0$ より大きく $1$ 以下のものは $\varphi(N)$ 個あります。

コード

def euler_phi(n):
    # 1 以上 n 以下で n と互いに素な整数の個数
    res = n
    p = 2
    while p * p <= n:
        if n % p == 0:
            res -= res // p
            while n % p == 0:
                n //= p
        p += 1
    if n > 1:
        res -= res // n
    return res


def phi_table(n):
    # phi[x] = φ(x)(0 <= x <= n、phi[0] = 0)
    phi = list(range(n + 1))
    for p in range(2, n + 1):
        if phi[p] == p:  # p は素数
            for x in range(p, n + 1, p):
                phi[x] -= phi[x] // p
    return phi