본 포스트는 e-maxx.ru/algo 의 영문 번역본인 cp-algorithms (e-maxx-eng) 를 한국어로 번역한 것입니다. e-maxx 포스트의 저자는 иванов максим 이며, cp-algorithms 포스트의 기여자는 여기서 확인하실 수 있습니다. 본 포스트는 CC-BY-SA-4.0 License를 따릅니다.
오일러 피 함수
오일러 피 함수 (Euler’s phi (totient) function)) 는 1부터 까지의 정수 중 과 서로소인 것의 개수를 세는 함수이다. 두 수의 최대공약수가 1일 때, 두 수는 서로소이다(1은 모든 수와 서로소인 것으로 간주된다).
처음 몇 개의 자연수에 대해 의 값은 다음과 같다:
성질
오일러 피 함수의 다음 성질들을 이용하여 모든 수에 대해 오일러 피 함수를 계산할 수 있다.
-
가 소수일 때, 모든 에 대해 이다. 따라서 다음 등식을 얻는다:
-
가 소수이고 일 때, 부터 까지의 수 중 정확히 개가 로 나누어 떨어진다. 따라서 다음 등식을 얻는다:
-
, 가 서로소일 때, 다음 등식을 얻는다:
이 관계는 자명해 보이지 않는다. 이 결과는 중국인 나머지 정리로부터 알 수 있는데, 중국인 나머지 정리에 의해 각 , 에 대해 , 를 만족하는 유일한 가 존재한다. 가 과 서로소임은 가 와 서로소이고 가 와 서로소임과 동치이다. 따라서 와 서로소인 정수의 개수는 , 의 곱과 같다.
-
서로소가 아닌 두 수 , 에 대해서, 등식 이 성립한다. 이때, 이다.
처음 세 성질과 의 소인수분해를 이용하여 를 계산할 수 있다. , 는 각각 소수일 때, 다음 등식이 성립한다.
구현
계산 복잡도의 소인수분해를 사용한 구현:
int phi(int n) {
int result = n;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
while (n % i == 0)
n /= i;
result -= result / i;
}
}
if (n > 1)
result -= result / n;
return result;
}
부터 까지 오일러 피 함수 구하기: 계산 복잡도
만약 부터 까지의 모든 수에 대해 오일러 피 함수값이 필요하다면, 각각의 수 개를 모두 소인수분해하는 것은 효율적이지 않다. 에라토스테네스의 체에서 썼던 아이디어를 적용할 수 있다. 위에서 보인 성질을 사용할 것이지만, 각각의 수에 대해 각 소인수마다 중간 결과를 갱신하는 대신, 우선 모든 소수를 찾은 후 각 소수에 대해 그로 나누어 떨어지는 모든 수에 대해 중간 결과를 갱신하는 방법을 사용한다.
이러한 접근은 근본적으로 에라토스테네스의 체와 같기 때문에, 계산 복잡도 또한 으로 같다.
void phi_1_to_n(int n) {
vector<int> phi(n + 1);
phi[0] = 0;
phi[1] = 1;
for (int i = 2; i <= n; i++)
phi[i] = i;
for (int i = 2; i <= n; i++) {
if (phi[i] == i) {
for (int j = i; j <= n; j += i)
phi[j] -= phi[j] / i;
}
}
}
약수 합 성질
이 흥미로운 성질은 가우스에 의해 확립되었다:
합은 의 모든 약수 에 대해 더한 것이다.
예를 들어, 10의 약수는 1, 2, 5, 10이다. 이 성립한다.
약수 합 성질을 이용하여 1부터 까지 오일러 피 함수값을 계산하기
약수 합 성질은 1부터 까지의 모든 오일러 피 함수값을 계산하는데 사용될 수 있다. 이 구현은 에라토스테네스의 체를 이용한 이전 구현보다 약간 더 간단하지만, 약간 더 나쁜 계산 복잡도인 을 갖는다.
void phi_1_to_n(int n) {
vector<int> phi(n + 1);
phi[0] = 0;
phi[1] = 1;
for (int i = 2; i <= n; i++)
phi[i] = i - 1;
for (int i = 2; i <= n; i++)
for (int j = 2 * i; j <= n; j += i)
phi[j] -= phi[i];
}
오일러 정리에서의 응용
오일러 피 함수의 가장 유명하고 중요한 성질은 오일러 정리에서 나타난다. 와 이 서로소일때, 다음 등식이 성립한다.
이 소수인 경우, 오일러 정리는 페르마의 소정리가 된다:
오일러 정리와 오일러 피 함수는 잉여 역수를 계산하는 데 활용되는 등 실전에서 자주 등장한다.
직접적인 결과로써 다음 합동식이 성립한다:
이 합동식을 통해 아주 큰 에 대해 을 계산할 수 있다. 특히 이 다른 계산의 결과인 경우, 을 법 에 대해 계산하여도 된다.
일반화
서로소가 아닌 , 에 대해 을 효율적으로 계산하는 마지막 합동식의 잘 알려지지 않은 변형이 있다. 임의의 와 에 대해 다음 합동식이 성립한다.
증명:
를 와 공통 소인수라고 하고, 를 가 을 나누는 횟수라고 하자. 으로 정의하면 와 는 서로소이다. 가 를 나누도록 하는 정수 중 가장 작은 것을 라고 하자. 를 가정하면 다음과 같이 쓸 수 있다:
세번째 줄과 네번째 줄 사이의 합동은 이므로 성립한다. , 일 때, , 임을 관찰하자.
와 는 서로소이므로, 오일러 정리를 사용하여 다음 공식을 얻는다.
가 아주 작으므로 (사실 이다) 이는 효율적으로 계산할 수 있다.
이 공식은 적용하기 어렵지만, 의 행동을 분석하기 위해 사용할 수 있다. 거듭제곱으로 이루어진 수열 은 첫 개의 항 이후 길이 인 순환에 진입한다. , 는 서로소이므로 를 얻는다. 특히, 은 으로 나누어 떨어진다. 따라서 이 순환이 길이 를 갖는다고 말할 수도 있다. 으로부터, 목표했던 더욱 간단한 공식을 얻는다:
연습문제
- SPOJ #4141 "Euler Totient Function" [Difficulty: CakeWalk]
- UVA #10179 "Irreducible Basic Fractions" [Difficulty: Easy]
- UVA #10299 "Relatives" [Difficulty: Easy]
- UVA #11327 "Enumerating Rational Numbers" [Difficulty: Medium]
- TIMUS #1673 "Admission to Exam" [Difficulty: High]
- UVA 10990 - Another New Function
- Codechef - Golu and Sweetness
- SPOJ - LCM Sum
- GYM - Simple Calculations (F)
- UVA 13132 - Laser Mirrors
- SPOJ - GCDEX
- UVA 12995 - Farey Sequence
- SPOJ - Totient in Permutation (easy)
- LOJ - Mathematically Hard
- SPOJ - Totient Extreme
- SPOJ - Playing with GCD
- SPOJ - G Force
- SPOJ - Smallest Inverse Euler Totient Function
- Codeforces - Power Tower