Euler Phi Function: φ(n)
정의
Euler Phi Function φ(n) 은 1 이상 n 이하 정수 중 n 과 서로소 (gcd = 1) 인 정수의 개수입니다.
φ(n) = |{ k : 1 <= k <= n, gcd(k, n) = 1 }|
예시:
- φ(1) = 1 (1은 모든 수와 서로소)
- φ(6) = 2 (1, 5 만 6과 서로소)
- φ(7) = 6 (소수이므로 1~6 모두 서로소)
- φ(12) = 4 (1, 5, 7, 11)
핵심 성질
소수에서의 값
소수 p 에 대해:
φ(p) = p - 1
1 부터 p-1 까지 모두 p 와 서로소이기 때문입니다.
소수 거듭제곱
φ(p^k) = p^k - p^(k-1) = p^(k-1) * (p - 1)
1 부터 p^k 까지 중 p 의 배수는 p^(k-1) 개이므로, 서로소인 수는 p^k - p^(k-1) 개입니다.
곱셈적 함수 (Multiplicative Function)
gcd(a, b) = 1 이면:
φ(ab) = φ(a) * φ(b)
이 성질로 소인수분해를 이용한 일반 공식을 유도할 수 있습니다.
일반 공식
n = p1^a1 * p2^a2 * … * pk^ak 이면:
φ(n) = n * Π (1 - 1/pi) (pi: n 의 서로 다른 소인수)
= n * (p1-1)/p1 * (p2-1)/p2 * ... * (pk-1)/pk
예: φ(12) = φ(2^2 * 3) = 12 * (1 - 1/2) * (1 - 1/3) = 12 * 1/2 * 2/3 = 4
오일러 정리 (Euler’s Theorem)
gcd(a, n) = 1 이면:
a^φ(n) ≡ 1 (mod n)
페르마 소정리 의 일반화입니다. 소수 p 에서 φ(p) = p-1 이므로 a^(p-1) ≡ 1 (mod p) 가 됩니다.
합 공식
Σ_{d | n} φ(d) = n
n 의 모든 약수 d 에 대한 φ(d) 의 합은 n 입니다.
시각화
φ(n) 의 곱셈적 분해 과정 (n = 60 = 2^2 * 3 * 5):
flowchart TD
N["phi(60)"]
N -->|"60 = 2^2 * 3 * 5"| D["곱셈적 분해"]
D --> A["phi(4) = 4 * (1 - 1/2) = 2"]
D --> B["phi(3) = 3 * (1 - 1/3) = 2"]
D --> C["phi(5) = 5 * (1 - 1/5) = 4"]
A --> R["phi(60) = 2 * 2 * 4 = 16"]
B --> R
C --> R
1 부터 60 까지 60 과 서로소인 수는 16 개입니다.
에라토스테네스의 체 방식으로 1 부터 N 까지 φ 를 일괄 계산하는 흐름:
flowchart LR
Init["phi[i] = i (초기화)"]
Init --> Loop["i = 2 to N"]
Loop -->|"phi[i] == i (소수)"| Prime["소수 i 발견"]
Prime --> Sieve["j = i, 2i, 3i, ... <= N\nphi[j] = phi[j] / i * (i-1)"]
Sieve --> Loop
Loop -->|"완료"| Done["phi[1..N] 완성"]
알고리즘
단일 n 에 대한 φ(n)
소인수분해 를 이용합니다. O(sqrt(n)).
euler_phi(n):
result = n
p = 2
while p * p <= n:
if n % p == 0:
while n % p == 0:
n /= p
result = result / p * (p - 1) // 정수 나눗셈 순서 주의
p += 1
if n > 1:
result = result / n * (n - 1) // n 이 소수
return result
1 부터 N 까지 일괄 계산 (시브)
에라토스테네스의 체 변형. O(N log log N).
euler_sieve(N):
phi[1] = 1
for i in 2..N:
phi[i] = i
for i in 2..N:
if phi[i] == i: // i 가 소수 (아직 변경 안 됨)
for j in i, 2i, 3i, ..., N:
phi[j] = phi[j] / i * (i - 1)
return phi
선형 시브 (Linear Sieve)
O(N). 각 합성수를 정확히 한 번만 처리합니다.
linear_sieve_phi(N):
phi[1] = 1
primes = []
for i in 2..N:
if not composite[i]:
primes.append(i)
phi[i] = i - 1
for p in primes:
if i * p > N: break
composite[i * p] = true
if i % p == 0:
phi[i * p] = phi[i] * p // p^2 | i*p
break
else:
phi[i * p] = phi[i] * (p - 1) // gcd(i, p) = 1
return phi
구현
// Euler Phi: 단일 값 + 시브
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// 단일 n 에 대한 phi(n), O(sqrt(n))
ll euler_phi(ll n) {
ll result = n;
for (ll p = 2; p * p <= n; p++) {
if (n % p == 0) {
while (n % p == 0) n /= p;
result = result / p * (p - 1);
}
}
if (n > 1) result = result / n * (n - 1);
return result;
}
// 1..N 시브, O(N log log N)
vector<int> euler_sieve(int N) {
vector<int> phi(N + 1);
iota(phi.begin(), phi.end(), 0); // phi[i] = i
for (int i = 2; i <= N; i++) {
if (phi[i] == i) { // i 가 소수
for (int j = i; j <= N; j += i) {
phi[j] = phi[j] / i * (i - 1);
}
}
}
return phi;
}
int main() {
ios::sync_with_stdio(0); cin.tie(0);
int t; cin >> t;
while (t--) {
ll n; cin >> n;
cout << euler_phi(n) << "\n";
}
}5
1
6
7
12
601
2
6
4
16복잡도
| 항목 | 값 |
|---|---|
| 단일 φ(n) | O(sqrt(n)) |
| 시브 φ(1..N) | O(N log log N) |
| 선형 시브 φ(1..N) | O(N) |
| 공간 | O(N) (시브) |
응용
모듈러 역원
모듈러 역원 계산: gcd(a, n) = 1 이면 a^(φ(n)-1) ≡ a^(-1) (mod n).
n 이 소수이면 φ(n) = n-1 이므로 a^(n-2) mod n 으로 계산합니다.
이산 로그 / 지수 주기
이산 로그 에서 지수의 주기가 φ(n) 의 약수임을 이용합니다.
오일러 정리 응용
a^b mod n 에서 b 가 매우 클 때: b >= φ(n) 이면 a^b ≡ a^(b mod φ(n) + φ(n)) (mod n).
곱셈적 함수 시브
φ 는 곱셈적 함수이므로 선형 시브 로 O(N) 에 계산 가능합니다. 다른 곱셈적 함수 (약수 개수, 약수 합 등) 도 같은 방식으로 계산합니다.
함정
WARNING
구현 시 자주 발생하는 실수들.
1. 정수 나눗셈 순서
result = result / p * (p - 1) 에서 /p 를 먼저 해야 합니다. result * (p-1) / p 로 하면 중간 값이 오버플로우할 수 있습니다.
2. 시브에서 소수 판별
phi[i] == i 조건으로 소수를 판별합니다. 초기화 시 phi[i] = i 로 설정하고, 소수의 배수를 처리할 때만 값이 바뀝니다.
3. n = 1 처리
φ(1) = 1 입니다. 단일 계산 함수에서 루프 후 n > 1 체크가 없으면 φ(1) = 0 이 됩니다.
4. 오일러 정리 조건
a^φ(n) ≡ 1 (mod n) 은 gcd(a, n) = 1 일 때만 성립합니다. gcd(a, n) > 1 이면 성립하지 않습니다.
5. 큰 지수 계산
a^b mod n 에서 b >= φ(n) 일 때 b mod φ(n) 으로 줄이는 공식은 gcd(a, n) = 1 일 때만 정확합니다. gcd(a, n) > 1 이면 별도 처리가 필요합니다.
BOJ 연습 문제
| 번호 | 제목 | 설명 |
|---|---|---|
| BOJ 11712 | 오일러 피 함수 | φ(n) 직접 계산 |
| BOJ 17646 | 소수의 개수와 소인수분해 | 시브 + 소인수분해 |
| BOJ 1837 | 암호제작 | 서로소 조건 활용 |
관련 위키
이 글의 용어 (8개)
- 모듈러 산술 (Modular Arithmetic)algorithm
- 정의 모듈러 산술 (Modular Arithmetic) 은 정수를 특정 수 $m$ 으로 나눈 나머지 로 대응시켜 다루는 산술 체계입니다. 합동 관계 $a \equiv b \pmo…
- 모듈러 역원 (Modular Multiplicative Inverse)algorithm
- 정의 정수 a 의 모듈러 역원 (modular multiplicative inverse) 은 을 만족하는 정수 x. 기호로 또는 . 존재 조건: gcd(a, m) = 1 일 때만…
- 소인수분해 (Prime Factorization)algorithm
- 정의 소인수분해 (Prime Factorization) 는 양의 정수 N을 소수들의 곱으로 유일하게 나타내는 것. N = p₁^a₁ · p₂^a₂ · ... · pₖ^aₖ. 시행…
- 에라토스테네스의 체 (Sieve of Eratosthenes)algorithm
- 정의 에라토스테네스의 체 (Sieve of Eratosthenes) 는 1부터 N 까지의 모든 소수를 O(N log log N) 에 찾는 고대 그리스 알고리즘. 기원전 240 년…
- 오일러 피 함수 (Euler's Totient Function)algorithm
- 정의 오일러 피 함수 φ(n) 는 1 이상 n 이하의 자연수 중 n 과 서로소인 수의 개수. 1763년 레온하르트 오일러가 도입. , 소수 p 에 대해 . 문제 상황과 동기 n …
- 이산 로그 (Discrete Logarithm)algorithm
- 정의 이산 로그 (Discrete Logarithm) 는 군 G 에서 를 만족하는 최소 음이 아닌 정수 x 를 찾는 문제. 실수 로그와 달리, mod 연산 아래에서의 역연산은 어…
- 페르마 소정리 (Fermat's Little Theorem)algorithm
- 정의 페르마 소정리 (Fermat's Little Theorem, FLT) 는 소수 p 와 gcd(a, p) = 1 인 정수 a 에 대해 다음이 성립: 1640년 피에르 드 페르…
- Carmichael Function λ(n)algorithm
- 정의 Carmichael function λ(n) 은 gcd(a, n) = 1 인 모든 a 에 대해 a^m ≡ 1 (mod n) 을 만족하는 최소 양의 정수 m 입니다. 핵심 성…
💬 댓글