오일러 프로젝트 23

자신을 제외한 약수(진약수)를 모두 더하면 자기 자신이 되는 수를 완전수라고 합니다. 예를 들어 28은 1 + 2 + 4 + 7 + 14 = 28 이므로 완전수입니다. 또, 진약수의 합이 자신보다 작으면 부족수, 자신보다 클 때는 초과수라고 합니다. 12는 1 + 2 + 3 + 4 + 6 = 16 > 12 로서 초과수 중에서는 가장 작습니다. 따라서 초과수 두 개의 합으로 나타낼 수 있는 수 중 가장 작은 수는 24 (= 12 + 12) 입니다.

해석학적인 방법을 사용하면, 28123을 넘는 모든 정수는 두 초과수의 합으로 표현 가능함을 보일 수가 있습니다. 두 초과수의 합으로 나타낼 수 없는 가장 큰 수는 실제로는 이 한계값보다 작지만, 해석학적인 방법으로는 더 이상 이 한계값을 낮출 수 없다고 합니다.

그렇다면, 초과수 두 개의 합으로 나타낼 수 없는 모든 양의 정수의 합은 얼마입니까?

http://euler.synap.co.kr/prob_detail.php?id=23

접근

문제에서 제시했듯이 가장 작은 초과수가 12이므로, 24~28123 사이의 모든 수에 대해서 초과수 두 개의 합으로 나타낼 수 있는지를 찾으면 된다. 두 초과수의 합으로 N을 나타낼 수 있는지를 검사하기 위해서, 초과수 집합에 대해 두 번 루프를 돌면서 A + B == N을 만족하는지를 찾으면 너무 비효율적이므로, 다음과 같은 방식으로 검사 시간을 줄이도록 한다.

  1. 28111 이하의 모든 초과수의 집합을 구한다.(23123-12). 이 집합을 A라 하자.
  2. 24이상의 임의의 자연수 N에 대해서 N보다 작은 A의 원소 하나를 뺀다. 그리고 그 뺀 값이 A에 포함되어 있는지를 본다. 포함되어 있다면 N은 두 개의 초과수의 합임을 확인할 수 있다.
  3. N보다 작은 초과수 중에서 2를 만족하는 값이 없다면 N은 두 개의 초과수의 합으로 나타낼 수 없는 값이다. (실제로는 N의 절반까지만 체크하면 된다.)
  4. 3에서 구한 수들과 1~23 사이의 자연수를 모두 더하면 답이 된다.

이번 문제 역시 만 단위 숫자의 약수의 합을 구하는 것이기 때문에, 무식하게(?) 약수의 합을 구하는 함수를 사용하는 것으로 충분하다.

def facsum(n: int) -> int:
    l = int(n**0.5 + 0.5)
    s = 1 - (l if l * l == n else 0)
    for a in range(2, l + 1):
        if n % a == 0:
            s += a + n // a
    return s


def isovernum(n: int) -> bool:
    return facsum(n) > n


fs = [x for x in range(1, 28123) if isovernum(x)]
v = set(fs)


def test(n: int) -> int:
    if n < 24:
        return True
    for x in fs:
        if x > n // 2:
            break
        if (n - x) in v:
            return False
    return True


def main():
    print(sum(filter(test, range(1, 28123))))


if __name__ == "__main__":
    main()

Read more

워드프레스에서 고스트로 이전

워드프레스에서 고스트로 이전

이 글을 쓰면서도 믿기 힘든 사실인데, 블로그라는 걸 처음 시작한지가 20년이 되었습니다. 이글루스에서 처음 시작했다가, SK컴즈가 인수한다고 발표함과 동시에 워드프레스로 플랫폼을 옮겼죠. 워드프레스오 옮긴 이후에는 호스팅 환경을 이리 저리 옮기긴 했지만 거의 18년 가까이 워드프레스를 사용해온 것 같습니다. 그 동안 워드프레스는 블로깅 툴에서 명실상부한 범용CMS로 발전했습니다. 사실 웬만한 홈페이지들은 이제

By sooop
띄어쓰기에 대한 생각

띄어쓰기에 대한 생각

업무 메일을 쓸 때 가장 많이 쓰는 말 중에 하나가 메일 말미에 ‘업무에 참고 부탁 드립니다.‘인데요, 어느 날부터 아웃룩에서 이 ‘부탁 드립니다’가 틀렸다고 맞춤법 지적을 하기 시작했습니다. 맞는 말은 ‘부탁드립니다’라고 붙여 쓰는 거라고. 사실 아래아한글 시절부터 이전의 MS워드까지, 워드프로세서들의 한국어 맞춤법 검사 실력은 거의 있으나 마나 한

By sooop

구글 포토에서 아이클라우드로 탈출한 후기

한 때 구글 포토가 백업 용량을 무제한으로 제공해 주겠다고해서, 구글 포토를 사용해서 사진을 백업해왔습니다. 물론 이 이야기의 결말은 저나 이 글을 읽고 있는 여러분이나 모두 알고 있습니다. 사실 AI에게 학습 시킬 이미지 데이터를 모으기 위한 것일 뿐이라거나 하는 이야기는 그 당시에도 있었습니다만, 에이 그래도 구글인데 용량은 넉넉하게 주겠지…하는 순진한

By sooop

Julia의 함수 사용팁

연산자의 함수적 표기 Julia의 연산자는 기본적으로 함수이며, 함수 호출 표기와 같은 방식으로 호출하는 것이 가능합니다. 또한 그 자체로 함수이기 때문에 filter(), map() 과 같이 함수를 인자로 받는 함수에도 연산자를 그대로 적용하는 것이 가능합니다. 특히 + 연산자는 sum() 함수와 같이 여러 인자를 받아 인자들의 합을 구할 수 있습니다. 2 + 3 # = 5 +(2,

By sooop