정규수(Normal number)라는 개념이 있다.

그리고, 극단적인 정규수로 챔퍼나운 상수(Champernowne's constant)가 있다.


이 문제는 챔퍼나운 상수의 1, 10, 100, 1000, 10000, 100000, 1000000 자리 숫자의 곱을 구하는 문제다.

근데, 정규수와 챔퍼나운 상수의 수학적 의미와 별개로 이 문제는 숫자만 나열하면 되는 문제라 의외로 쉽다.


처음부터 일일이 다 늘어놓는 방법도 있지만, 그건 좀 심하고, 조금만 생각을 해보면 계산을 많이 줄일 수 있다.


1. 1~9자리는 그대로 1~9임

2. 10~99의 90개는 2자리임

3. 100~999의 900개는 3자리임, 이후도 같은 규칙임


이런 규칙들을 염두에 두면 대략 아래와 같은 코드가 나온다.


#include <cstdio>
#include <cmath>

unsigned nDigitBegin(unsigned digit)
{
    unsigned count = 1;
    for (unsigned i = 1; i < digit; i++) {
        count *= 10;
    }
    return count;
}

unsigned getNthDigit(unsigned n)
{
    if (n < 10) return n;
    // 1~9 : 1자리
    // 10~99: 2자리 (90개)
    // 100~999: 3자리 (900개)

    // 이 sum은 자리수의 합을 의미함. 숫자의 합이 아님
    unsigned sum = 9;
    unsigned digit = 1;
    while (sum < n) {
        digit++;
        sum += digit * 9 * nDigitBegin(digit);
    }

    // 결과는 digit 자리 내에 있음
    // 한 자리 백
    sum -= digit * 9 * nDigitBegin(digit);
    // 현재까지의 자리수의 합은 sum

    unsigned from = nDigitBegin(digit);
    // 숫자는 from 부터 시작함

    int count = (n - sum - 1) / digit;
    // 현재부터 count개 다음에 시작된다는 뜻임

    sum += digit*count;
    from += count;

    static char str[10];
    sprintf_s(str, 10, "%u", from);

    return (str[n-sum-1]-'0');
}

int main(int argc, char* argv[])
{
    printf("-= Champernowne's constant =-\n");
    unsigned product = 1;
    for (unsigned i = 0, digit = 1; i < 7; i++, digit *= 10) {
        unsigned nthDigit = getNthDigit(digit);
        printf("d(%u) = %u\n", digit, nthDigit);
        product *= nthDigit;
    }
    printf("product = %u\n", product);
    return 0;
}

결과는 아래와 같다.


-= Champernowne's constant =-
d(1) = 1
d(10) = 1
d(100) = 5
d(1000) = 3
d(10000) = 7
d(100000) = 2
d(1000000) = 1
product = 210



신고

+ Recent posts