반응형

 

짧고 간결한 프로젝트 오일러 문제 하나.

제목에서도 적었듯이 n제곱 해서 나온 숫자의 자릿수가 n인 모든 경우를 묻는 것이다.

다른 문제도 그렇지만, 이 문제는 일일이 제곱을 해가며 풀 수도 있다.

제곱의 결과가 64비트 범위를 넘어설 수도 있으니 이 부분을 해결할 아이디어만 있으면 된다.

 

하지만 그런 무식한(?) 방법보다는 로그를 활용하는 것이 훨씬 더 좋다.

 

일단 10진수 D의 자릿수가 n이라는 건 \(n-1 \leq log _{10} D \lt n\) 이라고 쓸 수 있다.

또한, 문제의 특성상 지수의 밑은 오로지 1~9 까지만 가능하다.

 

다시 말해서 \(1 \leq d \leq 9\) 인 자연수 d에 대해서 \(n-1 \leq log _{10} d ^ {n} \lt n\) 인 자연수 n의 개수를 세면 되는 것이다.

이 식은 로그의 특성을 고려하면 \(\frac {n-1}{n} \leq log _{10} d \lt 1\) 로 정리할 수 있다.

그런데, 애초에 \(log _{10}{ d }\) 는 1보다 작을 수밖에 없어 오른쪽 부등호는 없어도 된다.

 

이 내용을 그대로 코드로 표현하면 아래와 같다.

 

#include <iostream>
#include <cmath>

using namespace std;

int main()
{
    int count = 0;
    for (int d = 1; d < 10; ++d) {
        double l10d = log10(d);
        
        for (int n = 1; ; ++n) {
            double ratio = (n - 1) / (double)n;
            if (ratio <= l10d) {
                cout << d << "^" << n << endl;
                ++count;
            }

            if (ratio > l10d) {
                break;
            }
        }
    }

    cout << count << "EA" << endl;
}

 

그런데, 조금만 생각해보면 안쪽 루프 자체를 제거해서 코드를 더 최적화할 수 있다.

 

\(\frac {n-1}{n} \leq log _{10} d\) 는 \(\frac {1}{n} \geq 1 - log _{10} d\) 로 정리하면 다시 \(n \leq \frac {1}{ 1 - log _{10} d}\) 로 정리할 수 있다.

여기서 n은 1 이상이어야 하므로 단순히 \(\left [ \frac {1}{ 1 - log _{10} d} \right ]\) 만 누적하면 똑같은 결과를 얻을 수 있다.

 

#include <iostream>
#include <cmath>

using namespace std;

int main()
{
    int count = 0;
    for (int d = 1; d < 10; ++d) {
        double l10d = log10(d);

        int x = (int)(1.0 / (1 - l10d));
        cout << x << endl;
        count += (int)x;
    }

    cout << count << "EA" << endl;
}

 

반응형

공유하기

facebook twitter kakaoTalk kakaostory naver band