문제 링크
- http://icpc.me/9537
문제 출처
- 2013 CERC C번
사용 알고리즘
- 분할정복
시간복잡도
- $O(N \log N)$
풀이
모든 구간을 확인해야 하므로 분할 정복을 생각해봅시다. 구체적으로, 어떤 $m$에 대해 $A[m]$을 지나는 모든 구간들 중 잘생긴 GCD의 최댓값을 구할 수 있어야 합니다.
가장 먼저 생각해볼 수 있는 방법은, 왼쪽 방향으로 $(A[m], 1), (\text{gcd}(A[m-1\cdots m]), 2), \cdots (\text{gcd}(A[1\cdots m]), m)$을, 오른쪽 방향으로 $(A[m], 1), (\text{gcd}(A[m\cdots m+1]), 2), \cdots (\text{gcd}(A[m\cdots N]), N-m+1)$을 구한 뒤, 2중 반복문을 이용해 모든 구간을 보는 방법이 있습니다. 이때의 시간 복잡도는 $O(N^2)$이므로 $T(N) = 2T(N/2) + O(N^2) = O(N^2)$이 됩니다.
이 풀이의 연산량을 줄이는 방법은 무엇이 있을까요? 각 방향으로 순서쌍을 구할 때, gcd값이 같다면 $m$에서 가장 멀리 떨어진 지점만 저장하는 방식으로 커팅을 할 수 있습니다. 그리고 이 커팅을 적용하면 AC를 받을 수 있습니다.
그 이유는, gcd가 바뀔 때마다 매번 2배 이상 줄어들기 때문에 서로 다른 gcd값만 저장하면 $O(\log X)$개만 저장됩니다. 그러므로 시간 복잡도는 $T(N) = 2T(N/2) + O(N + \log^2 N) = T(N \log N)$이 됩니다.
전체 코드
1 |
|