Doby's Lab

백준 19577번: 수학은 재밌어 (C++) 본문

PS/BOJ

백준 19577번: 수학은 재밌어 (C++)

도비(Doby) 2022. 8. 4. 22:58

https://www.acmicpc.net/problem/19577

 

19577번: 수학은 재밌어

xφ(x) = n을 만족하는 양의 정수 x가 존재하면 최소의 x를, 존재하지 않으면 −1을 출력한다.

www.acmicpc.net


Solved By: Euler Phi Function

 

(x) = n에서 얻어낼 수 있는 정보는 x는 n의 약수라는 것입니다. 즉, n 이하의 모든 양의 정수를 탐색할 필요가 없다는 뜻입니다.

n의 약수를 전부 얻어낼 수 있게 코드를 짭니다.

다음은 Euler Phi를 구현해야 하는데 이전 문제에서는 계속 폴라드 로를 사용해서 구현을 했었는데 소인수의 개수를 알 필요 없이 어떤 소인수만 가지는지 알면 되기 때문에 폴라드 로를 사용하지 않고 구해봅시다.

 

(출처: https://nevertheless-intheworld.tistory.com/17)

코드를 보면 n != 1이 아닌 조건에서 한 번 더 오일러 피 함수 계산을 해줍니다. 그런데 왜 한 번인가요?

이 질문에 대한 답은 가정을 해보면서 답을 구했습니다. 아래의 코드에 주석으로 달아두었습니다.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int eulerPhi(int n){
    int ret = n;
    for(int i = 2; i * i <= n; i++){
        if(n % i == 0){
            ret *= (i - 1);
            ret /= i;
            while(n % i == 0) n /= i;
        }
    }
    // 왜 한 번 밖에 체크 하지 않나?
    // n이라는 합성수의 약수 중 sqrt(n)이상의 소수는
    // 최소 1번만 나올 수 밖에 없다.
    // n = p0 * p1이라고 가정하고, p는 소수,
    // p0 <= sqrt(n), p1 >= sqrt(n)이라고 하면
    // 다른 소수의 조합으로는 n을 만들 수가 없기 때문이다.
    if(n != 1){
        ret *= (n - 1);
        ret /= n;
    }
    return ret;
}

int main(){
    int n; cin >> n;
    
    vector<int> factors;
    for(int i = 1; i * i <= n; i++){
        if(n % i == 0){
            factors.push_back(i);
            if(n / i != i){
                factors.push_back(n / i);
            }
        }
    }
    sort(factors.begin(), factors.end());
    for(auto v : factors){
        if(v * eulerPhi(v) == n){
            cout << v;
            return 0;
        }
    }
    
    cout << -1;
    return 0;
}

 

728x90