오일러 함수의 성질과 계산 방법

오일러 함수 φ(n)은 1부터 n까지 n과 서로 소인 수의 개수를 나타냅니다. 두 수 a와 b가 서로 소일 때 gcd(a,b)=1이 성립합니다.

재귀적 계산식
임의의 양의 정수 a에 대해 다음 식이 성립합니다:

φ(ab) = φ(a)×φ(b)×gcd(a,b)/φ(gcd(a,b))
a와 b가 서로 소일 경우 φ(ab) = φ(a)×φ(b)가 됩니다.

증명
n을 소인수 분해한 후 φ(n)을 계산하는 방식을 통해 증명할 수 있습니다. d = gcd(a,b)라고 하면:

φ(ab) = [φ(a)×φ(b)×d]/φ(d) = ab×∏(1-1/p_i) 로 변환됩니다.
이는 a와 b의 공통 소인수를 제거하여 φ(n)의 정의에 부합함을 보여줍니다.

일반항 공식
n의 소인수 분해 결과를 기반으로 다음과 같이 계산할 수 있습니다:

φ(N) = N × ∏(1 - 1/p_i) (p_i는 소인수)

증명 방법
n = p₁^b₁ × p₂^b₂ × ... × p_k^b_k 형태로 표현하면:

φ(n) = n × ∏(1 - 1/p_i)
각 소인수의 지수에 관계없이 φ(n)의 값이 결정됨을 보여줍니다.

포함-배제 원리 활용
n의 소인수 p₁,p₂,...,p_k에 대해:

φ(n) = n - Σ(n/p_i) + Σ(n/(p_i p_j)) - ...
이를 정리하면 φ(n) = n × ∏(1 - 1/p_i) 형태로 변환됩니다.

효율적인 계산
소인수 분해 시간 복잡도 O(√n)을 갖는 알고리즘으로 φ(n)을 구현할 수 있습니다.


#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

int main() {
    int T;
    cin >> T;
    while (T--) {
        int num;
        cin >> num;
        int result = num;
        for (int i = 2; i <= sqrt(num); i++) {
            if (num % i == 0) {
                result = result / i * (i - 1);
                while (num % i == 0) num /= i;
            }
        }
        if (num > 1) result = result / num * (num - 1);
        cout << result << endl;
    }
    return 0;
}

선형 체계 활용
O(n) 시간 복잡도를 가진 선형 체계 기반 알고리즘입니다:


#include <iostream>
#include <vector>

using namespace std;

const int MAX = 1000010;
vector<int> primeList;
bool sieveFlags[MAX];
int phiValues[MAX];

int main() {
    int n;
    cin >> n;
    phiValues[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!sieveFlags[i]) {
            primeList.push_back(i);
            phiValues[i] = i - 1;
        }
        for (int j = 0; j < primeList.size() && i * primeList[j] <= n; j++) {
            sieveFlags[i * primeList[j]] = true;
            if (i % primeList[j] == 0) {
                phiValues[i * primeList[j]] = phiValues[i] * primeList[j];
                break;
            } else {
                phiValues[i * primeList[j]] = phiValues[i] * (primeList[j] - 1);
            }
        }
    }
    cout << accumulate(phiValues, phiValues + n + 1, 0) << endl;
    return 0;
}

태그: 수론 알고리즘 선형_체계 유레라_함수 소인수_분해

7월 11일 23:00에 게시됨