사용자 도구

사이트 도구


ps:problems:boj:8229

Fibonacci Representation

ps
링크acmicpc.net/…
출처BOJ
문제 번호8229
문제명Fibonacci Representation
레벨플래티넘 4
분류

그리디

시간복잡도O(t*logn)
인풋사이즈t<=10, n<=4*10^17
사용한 언어Python
제출기록30840KB / 68ms
최고기록60ms
해결날짜2022/04/28

풀이

  • 그리디하게, 만들려는 수에 가장 근접한 피보나치 수를 찾아서 포함시키는 방식으로 반복하면 찾을 수 있다.
    • f(n) 이하의 피보나치 수들만을 더해서 만들어진 수가 f(n+1)이상이라면, 이것을 f(n+1)을 포함하는 피보나치수의 합으로 바꿔 쓰는 것이 항상 가능하고, 이 경우에 더해지는 피보나치수의 갯수가 증가하지는 않는다.
    • Zeckendorf's_theorem도 참고하자.
  • 만들려는 수에 가장 근접한 피보나치 수를 찾는 것은 몇가지 방법이 있는데.. 만들려는수가 x이고, F(m) <= n < F(m+1)인 F(m)과 F(m+1)을 구하는거라고 하자. 그러면 m은 O(logn)이다.
    • 그냥 전처리 없이 F(1),F(2),… 를 계속 만들어가면서 찾는다면 O(m)
    • F(i)을 모두 전처리해서 O(m)에 미리 구해놓고서, 이분탐색으로 찾는다면 O(logm)
    • 피보나치 수의 일반식 $F_{n}=\left\lfloor {\frac {\varphi ^{n}}{\sqrt {5}}}+{\frac {1}{2}}\right\rfloor$ 을 역으로 써서 $n(F)=\left\lceil \log _{\varphi }\left(F\cdot {\sqrt {5}}-{\frac {1}{2}}\right)\right\rceil $으로 계산하는 방법
      • O(1)에 m을 구할수 있고.. F(i)을 모두 전처리해서 미리 구해놨다면 F(m)을 구하는 것까지도 O(1)이겠지만.. 계산도 복잡하고 실수오차도 있을거 같은 느낌..
    • 결국은 m자체가 별로 크지 않으니까 (n⇐4*10^17 문제조건에서 m은 100 이하이다) 가장 간단한 첫번째 방법으로 구현했다. 이 방식으로 m 개의 항을 구해도 O(m^2) = O(log^2(n))이다
  • O(m^2)으로 풀고 나서, 다른 사람 답안을 보다가 훨씬 좋은 방법을 알게 되었다. n에 가장 근접한 피보나치 수 F(m)을 찾아서 빼 준다음에, n-F(m)에 가장 근접한 피보나치 수를 찾으려고 할때, 다시 F(0)부터 만들어나가며 찾을 필요가 없다. F(m-1)에서부터 아래로 내려오면서 찾으면 되고, 이런식으로 접근하면 피보나치수들을 다시 한번씩만 만들게 되면 끝나므로, 결국 O(m^2)이 아니라 O(m)에 해결 가능하다.
    • 실제 수행시간은 m이 작아서 시간차이는 하나도 안난다.

코드

코드 1 - O(t*log^2(n))

"""Solution code for "BOJ 8229. Fibonacci Representation".

- Problem link: https://www.acmicpc.net/problem/8229
- Solution link: http://www.teferi.net/ps/problems/boj/8229

Tags: [Greedy]
"""


def main():
    p = int(input())
    for _ in range(p):
        k = int(input())

        answer = 0
        while k:
            a, b = 1, 1
            while b <= k:
                a, b = b, a + b
            k = min(b - k, k - a)
            answer += 1

        print(answer)


if __name__ == '__main__':
    main()

코드 2 - O(t*logn)

"""Solution code for "BOJ 8229. Fibonacci Representation".

- Problem link: https://www.acmicpc.net/problem/8229
- Solution link: http://www.teferi.net/ps/problems/boj/8229

Tags: [Greedy]
"""


def main():
    p = int(input())
    for _ in range(p):
        k = int(input())

        answer = 0
        a, b = 1, 1
        while b <= k:
            a, b = b, a + b
        while k:
            while a > k:
                a, b = b - a, a
            k = min(b - k, k - a)
            answer += 1

        print(answer)


if __name__ == '__main__':
    main()

토론

댓글을 입력하세요:
T L B O Z
 
ps/problems/boj/8229.txt · 마지막으로 수정됨: 2022/04/28 08:40 저자 teferi